Blog

Auf dem Weg zu Perl 5.36 – Signaturen

28.04.2022 // Renée Bäcker

Nicht einmal 1 Monat, dann wird es die nächste Version von Perl 5 geben: Perl 5.36. Um die Wartezeit etwas zu verkürzen, werden wir hier ein paar Neuerungen vorstellen. Der erste Teil hat dann aber etwas zum Thema, das gar nicht mehr so neu ist: (Methoden-)Signaturen. Schon seit Perl 5.20 (also rund acht Jahre) gibt es die Signaturen. Aber jetzt endlich sind sie nicht mehr als experimentell gekennzeichnet.

Mit den Signaturen kann der Code übersichtlicher gestaltet werden und man automatisch eine Überprüfung der Anzahl der übergebenen Parameter dabei.

Der einfachste Fall sind verpflichtende Parameter:

use v5.35; # aktiviert auch strict und warnings

crawl( 'https://perl-academy.de' );

sub crawl ($url) {
    say "URL: $url";
    
    # hole die Seite und extrahiere die Links
    # siehe Beispielcode im Git-Repository
}

Hier hat die Subroutine crawl genau einen Pflichtparameter – $url. Die Variable muss nicht extra deklariert werden und diese ist nur in der Subroutine gültig. In der Subroutine selbst kann ganz normal mit der Variablen gearbeitet werden.

In diesem Beispiel ersetzt das

sub crawl ($url) {
}

mehr oder weniger nur ein

sub crawl {
    my ($url) = @_;
}

Sieht erst einmal nach nicht viel aus. Mit der Verwendung der Signaturen gibt es aber eine Prüfung der Anzahl an übergebenen Parameter. Der Aufruf crawl() erzeugt dann die Fehlermeldung

Too few arguments for subroutine 'main::crawl' (got 0; expected 1)

und der Aufruf crawl('https://perl-academy.de', 1) erzeugt die Fehlermeldung

Too many arguments for subroutine 'main::crawl' (got 2; expected 1)

Möchte man etwas flexibler in den Aufrufen sein, muss also etwas an den Signaturen geändert werden. Eine Möglichkeit ist, slurpy Parameter zu nutzen. Soll crawl beliebig viele Parameter akzeptieren, kann man

sub crawl ($url, @more_parameters) {
}

nutzen. Damit landet der erste übergebene Parameter in $url und alle weiteren Parameter in @more_parameters. Es kann auch ein Hash benutzt werden:

sub crawl ($url, %opts) {
}

Damit landet bei einem Aufruf mit crawl('https://perl-academy.de', max_redirects => 2) die URL in $url und im Hash %opts gibt es den Schlüssel max_redirects mit dem Wert 2.

Aber diese beiden Möglichkeiten sind nicht immer die beste Wahl, weil dann unterschiedliche Parameter in einem Array landen. Deshalb gibt es auch die Möglichkeit, mittels default-Werten die Parameter optional zu machen und sie mit einem vorgegebenen Wert zu belegen:

sub crawl ($url, $max_redirects = 2) {
}

Bei einem Aufruf mit crawl('https://perl-academy.de', 5) ist der Wert von $max_redirects natürlich 5, bei einem Aufruf mit crawl('https://perl-academy.de' ) ist der Wert der Variablen 2.

Der default-Wert muss nicht nur eine Zahl oder ein String sein, sondern kann ein Subroutinen-Aufruf sein, vorherige Parameter können verwendet werden und auch ein do{}-Block ist möglich:

sub crawl ($url, $max_redirects = get_config('max_redirects') ) {
}

sub crawl ($url, $api_url = $url . '/api/v1' ) {
}

sub crawl ( $url, $max_redirects = do { warn "Using default value"; 2; } ) {
}

Es gibt noch die Möglichkeit, unbenannte Variablen zu nutzen, wenn man an der Verwendung von Werten nicht interessiert ist. Die Verwendung dieser unbenannten Variablen ist unter https://metacpan.org/release/SHAY/perl-5.35.11/view/pod/perlsub.pod#Signatures nachzulesen. Das würde diesen Blogartikel zu sehr ausdehnen und diese Variablen spielten bisher bei in meinem Code keine Rolle.

Was Signaturen nicht bietet, sind Prüfungen von Datentypen. Es wird also nicht geprüft, ob der übergebene Skalar eine Arrayreferenz, Hashreferenz oder einfach ein String ist. Das muss weiterhin selbst gemacht werden. Auch benannte Parameter (beispielsweise crawl( url => 'https://perl-academy.de') ) sind derzeit nicht möglich.

Aber schon die gezeigten Möglichkeiten können das Programmieren stark vereinfachen.

Der Beispielcode ist im Git-Repository unter https://os.perl-services.de/perl-academy/blog-codesamples/-/tree/main/2022/04/5_36_signaturen zu finden.



Permalink: