index | project | pods | responsabili

NOME

perlsyn - La sintassi del Perl


DESCRIZIONE

Un programma Perl consiste in una sequenza di dichiarazioni e istruzioni che vengono eseguite dall'inizio alla fine. Cicli, subroutine e altre strutture di controllo vi permettono di saltare all'interno del codice.

Perl è un linguaggio free-form [A forma libera, NdT], potete formattarlo e indentarlo come preferite. Lo spazio bianco serve generalmente a separare i simboli, diversamente da altri linguaggi come Python dove è un'importante parte della sintassi.

Molti degli elementi sintattici del Perl sono opzionali. Piuttosto che richiedere di mettere le parentesi ad ogni chiamata a funzione e di dichiarare ogni variabile, spesso potete omettere questi elementi espliciti e Perl cercherà di capire cosa intendete. Questo è conosciuto come Do What I Mean [Fa quello che intendo, NdT], abbreviato DWIM. Ciò permette ai programmatori di essere pigri e di scrivere il codice in uno stile a loro confortevole.

Il Perl adotta sintassi e concetti da molti linguaggi: awk, sed, C, Bourne Shell, Smalltalk, Lisp e perfino dall'inglese. Altri linguaggi hanno preso in prestito la sintassi da Perl, in particolare le estensioni delle sue espressioni regolari. Cosí se avete già programmato con un altro linguaggio troverete frammenti familiari in Perl. Spesso funzionano allo stesso modo, ma consultate perltrap per informazioni su cosa differiscono.

Dichiarazioni

Le uniche cose che avete bisogno di dichiarare in Perl sono i formati dei report e le subroutine (e a volte nemmeno le subroutine). Una variabile contiene il valore indefinito (undef) finché non le viene assegnato un valore definito, cioé qualsiasi valore divero da undef. Quando è usato come numero, undef viene considerato come 0; quando è usato come stringa viene considerato la stringa vuota, ""; e quando viene utilizzato come riferimento che non è stato ancora assegnato, viene considerato come errore. Se abilitate i warnings [letterlmente avvertimenti, con use warnings, NdT], vi verrà notificato l'uso di un valore non inizializzato, ogni volta che tratterete undef come stringa o come numero. Beh, di solito. Contesti booleani come:

    my $a;
    if ($a) {}

sono esenti da avvertimenti (perché sono casi in cui importa la veridicità piuttosto che la definizione). Operatori come ++, --, +=, -= e .=, quando operano su variabili indefinite come:

    my $a;
    $a++;

sono anch'essi esenti da questi avvertimenti.

Una dichiarazione può essere posta ovunque si possa mettere un'istruzione, ma non ha effetti sulla sequenza primaria delle istruzioni--le dichiarazioni hanno tutte effetto al momento della compilazione. Tipicamente tutte le dichiarazioni vengono poste all'inizio o alla fine di uno script. Tuttavia, se state usando una variabile lessicale privata creata con my() dovete assicurarvi che la definizione del vostro formato o della subroutine sia nello stesso blocco del my per essere in grado di accedere a queste variabili private.

Dichiarare una subroutine permette di usare il nome di quella subroutine come operatore di lista da quel punto in poi del programma. Potete dichiarare una subroutine senza definirla usando sub nome, così:

    sub mionome;
    $io = mionome $0   or die "impossibile utilizzare mionome";

Va notato che mionome() funziona come operatore di lista, non come operatore unario; quindi, in questo caso, state attenti ad usare or invece di ||. Comunque, se dichiaraste la subroutine come sub mionome ($), allora mionome funzionerebbe come operatore unario, così sia or che || andrebbero bene.

Le dichiarazioni delle subroutine possono anche essere caricate con l'istruzione require, oppure sia caricate che importate nel vostro spazio dei nomi con l'istruzione use. Consultate perlmod per ulteriori dettagli.

Una sequenza di istruzioni può contenere delle dichiarazioni di variabili private, ma a parte questa funzione le dichiarazioni esse agiscono come istruzioni ordinarie, e vengono elaborate con il resto come se fossero istruzioni ordinarie. Questo significa che in realtà hanno degli effetti sia durante la compilazione che durante l'esecuzione.

Commenti

Il testo, dal carattere "#" sino alla fine della riga, è un commento e viene ignorato. Le eccezioni includono "#" all'interno di una stringa o di un'espressione regolare.

Istruzioni Semplici

L'unico tipo di istruzione semplice è un'espressione valutata per i suoi effetti secondari. Ogni istruzione semplice deve terminare con un punto e virgola, salvo che sia l'istruzione finale in un blocco nel quel caso è opzionale. (Un punto e virgola è tuttavia incoraggiato se il blocco è lungo più di una riga, così potete eventualmente aggiungere un'altra riga). Da notare che ci sono operatori come eval {} e do {} che sembrano istruzioni composte, ma non lo sono (sono solo TERMINI in un espressione), e perciò necessitano di un indicatore di terminazione explicito se sono usati come ultimo elemento in una espressione.

Verità e Falsità

Il numero 0, le stringhe '0' e '', la lista vuota () e undef risultano tutti falsi in un contesto booleano. Tutti gli altri valori sono veri. La negazione di un valore vero attraverso ! o not restituisce un valore falso speciale. Quando valutato come stringa viene trattato come '', ma come numero è considerato pari a 0.

Modificatori di Istruzione

Qualunque instruzione semplice può eventualmente essere seguita da un SINGOLO modificatore, subito prima del punto e virgola finale (o della fine del blocco). I possibili modificatori solo:

    if ESPRESSIONE
    unless ESPRESSIONE
    while ESPRESSIONE
    until ESPRESSIONE
    foreach LISTA

L'ESPRESSIONE che segue il modificatore è detta ``condizione''. La sua veridicità o falsità determina il modo in cui il modificatore dovrà comportarsi.

if esegue l'istruzione una volta se e solo se la condizione è vera. unless è l'opposto, ed esegue l'istruzione salvo che l'istruzione risulti vera (ossia, se la condizione è falsa).

    print "I basset hound hanno lunghe orecchie" if length $orecchie >= 10;
    vai_fuori() and gioca() unless $sta_piovendo;

Il modificatore foreach è un iteratore: esegue l'istruzione una volta per ogni elemento nella LISTA (con $_ che diventa un alias di ciascun elemento, volta per volta).

    print "Ciao $_!\n" foreach qw(mondo Dolly infermiera);

while ripete l'istruzione finché la condizione è vera. until fa l'opposto, cioé ripete l'istruzione fermandosi quando la condizione risulta vera.

    # Ciascuna istruzione conta da 0 a 10.
    print $i++ while $i <= 10;
    print $j++ until $j >  10;

I modificatori while e until hanno la tipica semantica del ``ciclo while'' (la condizione è valutata per prima), eccetto quando è applicata ad un BLOCCO do (oppure all'uso deprecato dell'istruzione do-SUBROUTINE), nel qual caso il blocco viene eseguito una volta prima che sia valutata la condizione. Così potete scrivere cicli come:

    do {
      $riga = <STDIN>;
           # ...
    } until $riga  eq ".\n";

Vedete perlfunc/do. Osservate inoltre che le istruzioni di controllo di ciclo descritte in seguito NON funzioneranno con questo costrutto, perché i modificatori non accettano etichette di ciclo. Spiacenti. Potete sempre mettere un altro blocco all'interno (per next) o all'esterno (per last) per fare questo genere di cose. Per next basta raddoppiare le parentesi graffe:

    do {{
       next if $x == $y;
       # qui si fa qualcosa
    }} until $x++ > $z;

Per last dovete essere più elaborati:

    CICLO: { 
            do {
          last if $x = $y**2;
          # qui si fa qualcosa
       } while $x++ <= $z;
    }

NOTA: Il comportamento di un'istruzione my modificata da un modificatore di istruzione o da un costrutto di ciclo (ad esempio, my $x if ...) è indefinito. Il valore della variabile my può essere undef, un qualunque valore assegnato in precedenza, o forse qualsiasi altra cosa. Non ci contate. Versioni future di perl potrebbero fare cose differenti rispetto alla versione che state utilizzando ora. Occhio ai dragoni.

Istruzioni Composte

In Perl, una sequenza di istruzioni che definisce uno scope viene chiamata blocco. A volte un blocco è delimitato dal file che lo contiene (nel caso di un file richiesto [con require, NdT], o il programma nella sua interezza), ed a volte un blocco è delimitato dalla lunghezza di una stringa (nel caso di una eval).

In generale, però, un blocco è delimitato da parentesi graffe. Chiameremo questo costrutto sintattico un BLOCCO.

Le istruzioni composte che seguono possono essere utilizzate per controllare il flusso del programma:

    if (ESPRESSIONE) BLOCCO
    if (ESPRESSIONE) BLOCCO else BLOCCO
    if (ESPRESSIONE) BLOCCO elsif (ESPRESSIONE) BLOCCO ... else BLOCCO
    ETICHETTA while (ESPRESSIONE) BLOCCO
    ETICHETTA while (ESPRESSIONE) BLOCCO continue BLOCCO
    ETICHETTA until (ESPRESSIONE) BLOCCO
    ETICHETTA until (ESPRESSIONE) BLOCCO continue BLOCCO
    ETICHETTA for (ESPRESSIONE; ESPRESSIONE; ESPRESSIONE) BLOCCO
    ETICHETTA foreach VAR (LIST) BLOCCO
    ETICHETTA foreach VAR (LIST) BLOCCO continue BLOCCO
    ETICHETTA BLOCCO continue BLOCCO

Osservate che, contrariamente a C e Pascal, queste sono definite in termini di BLOCCHI, non di istruzioni. Ciò significa che le parentesi graffe sono obbligatorie -- non sono ammesse istruzioni pendenti. Se volete scrivere condizioni senza parentesi graffe ci sono parecchi altri modi di farlo. Le seguenti istruzioni fanno tutte la stessa cosa:

    if (!open(PIPPO)) { die "Errore in open $PIPPO: $!"; }
    die "Errore in open $PIPPO: $!" unless open(PIPPO);
    open(PIPPO) or die "Errore in open $PIPPO: $!";  # PIPPO o morte!
    open(PIPPO) ? 'hi mom' : die "Errore in open $PIPPO: $!";
                        # un po' esotica, quest'ultima

L'istruzione if è banale. Poiché i BLOCCHI sono sempre circondati da parentesi graffe, non c'è mai ambiguità su quale if sia associato ad un particolare else. Se utilizzate unless al posto di if, il senso del test è invertito.

L'istruzione while esegue il blocco finché l'espressione è vera (ossia, non viene valutata come la stringa nulla "" o 0 o "0" [o anche undef, NdT]). L'istruzione until esegue il blocco finché l'espressione è falsa. L'ETICHETTA è opzionale e, se presente, consiste in un identificatore seguito da un carattere due-punti. L'ETICHETTA identifica il ciclo per le istruzioni di controllo dei cicli next, last e redo. Se l'ETICHETTA viene omessa, l'istruzione di controllo del ciclo si riferisce al ciclo più interno che la racchiude. Tutto ciò può implicare uno sguardo dinamico allo stack di chiamata in esecuzione per trovare l'ETICHETTA giusta. Un comportamento così disperato produce un avvertimento [``warning'', NdT] se utilizzate la direttiva use warnings o l'opzione -w.

Se c'è un BLOCCO continue, viene sempre eseguito immediatamente prima che la condizione venga valutata di nuovo. Per questo motivo, può essere utilizzato per incrementare la variabile di un ciclo, anche quando il ciclo viene fatto continuare con un'istruzione next.

Controllo di Ciclo

Il comando next fa partire l'iterazione successiva del ciclo:

    RIGA: while (<STDIN>) {
       next RIGA if /^#/;       # Scarta i commenti
       #...
    }

Il comando last esce immediatamente dal ciclo in questione. Il blocco continue, se presente, non viene eseguito:

    RIGA: while (<STDIN>) {
       last RIGA if /^$/;       # esci quando hai finito con l'intestazione
       # ...
    }

Il comando redo fa ripartire il ciclo senza valuatare la condizione di nuovo. Il blocco continue, se presente, non viene eseguito. Questo comando viene normalmente utilizzato da programmi che vogliono mentire a se stessi su quanto è stato appena inserito.

Ad esempio, quando elaborate un file come /etc/termcap. Se le vostre righe di ingresso potessero terminare con backslash per indicare continuazione, vorreste saltare avanti e prendere il record successivo.

    while (<>) {
       chomp;
       if (s/\\$//) {
          $_ .= <>;
          redo unless eof();
       }
       # ora si elabora  $_
    }

che è una scorciatoia Perl per la versione più esplicita:

    RIGA: while (defined($riga = <ARGV>)) {
       chomp($riga);
       if ($riga =~ s/\\$//) {
          $riga .= <ARGV>;
          redo RIGA unless eof(); # non eof(ARGV)!
       }
       # ora si elabora $riga
    }

Osservate che se ci fosse un blocco continue in questo codice, verrebbe eseguito solo in corrispondenza delle righe scartate dall'espressione regolare (poiché redo salta il blocco continue). Un blocco continue viene spesso utilizzato per riazzerare i contatori di riga o dei match di singoli ?pattern?:

    # ispirato da :1,$g/fred/s//WILMA/
    while (<>) {
       ?(fred)?    && s//WILMA $1 WILMA/;
       ?(barney)?  && s//BETTY $1 BETTY/;
       ?(homer)?   && s//MARGE $1 MARGE/;
    } continue {
       print "$ARGV $.: $_";
       close ARGV  if eof();            # riazzera $.
       reset        if eof();           # riazzera ?pattern?
    }

Se si sostituisce la parola until a while il senso del test è invertito, ma la condizione viene sempre verificata prima della prima iterazione.

Le istruzioni di controllo di ciclo non funzionano all'interno di if o unless, poiché questi non sono cicli. Potete però raddoppiare le parentesi graffe per renderli tali.

    if (/pattern/) {{
       last if /fred/;
       next if /barney/; # stesso effetto di "last", ma non documenta altrettanto bene
       # qui si fa qualcosa
    }}

Questo comportamento si ha perché quel blocco, di per sé, agisce come un ciclo che viene eseguito una volta sola, consultate BLOCCHI base ed Istruzioni Switch.

La forma while/if BLOCCO BLOCCO, disponibile in Perl 4, non esiste più. Rimpiazzate ogni occorrenza di if BLOCCO con if (do BLOCCO).

Cicli For

I cicli for stile C in Perl funzionano come il corrispondente ciclo while; ciò significa che questo:

    for ($i = 1; $i < 10; $i++) {
       # ...
    }

è la stessa cosa di:

    $i = 1;
    while ($i < 10) {
       # ...
    } continue {
       $i++;
    }

C'è una differenza minore: se le variabili sono dichiarate con my nella sezione di inizializzazione del for, lo scope lessicale di queste variabili coincide con il ciclo for (il corpo del ciclo e le sezioni di controllo).

Oltre al normale ciclo con l'indice di un array, for può prestarsi a molte altre applicazioni interessanti. Eccone una che evita il problema in cui vi trovate se effettuate esplicitamente il test di fine file su un descrittore di file interattivo, il che farebbe sembrare bloccato il programma.

    $su_una_tty = -t STDIN && -t STDOUT;
    sub richiedi { print "si'? " if $su_una_tty }
    for ( richiedi(); <STDIN>; richiedi() ) {
       # fai qualcosa
    }

Utilizzando readline (o la forma ad operatore, <ESPRESSIONE>) come condizionali per un ciclo for è una scorciatoia per quanto segue. Questo comportamento coincide con quello di una condizione in un ciclo while. >>

    for ( richiedi(); defined( $_ = <STDIN> ); richiedi() ) {
        # fai qualcosa
    }

Cicli Foreach

Il ciclo foreach itera su una normale lista ed imposta la variabile VAR come incarnazione di ciascun elemento della lista, in sequenza. Se la variabile è preceduta dalla parola chiave my, allora essa ha lo scope di un lessicale, ed è pertanto visibile solo all'interno del ciclo. Altrimenti, la vaiabile è implicitamente locale al ciclo e viene ripristinata al suo valore originale una volta usciti dal ciclo. Se la variabile era stata precedentemente dichiarata con my, viene utilizzata quella variabile invece che quella globale, ma è sempre localizzata al ciclo. Questa localizzazione implicita avviene solo in un ciclo foreach.

La parola chiave foreach è in realtà un sinonimo per la parola chiave for, di modo che potete utilizzare foreach per privilegiare la leggibilità o for per maggiore brevità. (O perché la shell Bourne potrebbe esservi più familiare di csh, quindi scrivere for verrebbe più naturale). Se VAR è omessa, $_ viene impostata a ciascun valore.

Se un qualunque elemento di LISTA è un lvalue [valore utilizzabile alla sinistra di un'assegnazione, NdT], potete modificarlo attraverso VAR all'interno del ciclo. Di contro, se un qualsiasi elemento in LISTA NON è un lvalue, qualsiasi tentativo di modificare quell'elemento fallirà. In altre parole, la variabile indice in un ciclo foreach è un alias implicito per ciascun elemento nella lista su cui state iterando.

Se una qualunque parte di LISTA è un array, foreach rimarrà decisamente confuso se aggiungete o rimuovete elementi all'interno del corpo del ciclo, ad esempio utilizzando splice. Per questo motivo, non fatelo.

foreach, probabilmente, non farà quel che vi aspettate se VAR è una variabile su cui è stata chiamata tie o se è un'altra variabile speciale. Non fate nemmeno questo.

Esempi:

    for (@ary) { s/foo/bar/ }
    for my $elem (@elementi) {
       $elem *= 2;
    }
    for $contatore (10,9,8,7,6,5,4,3,2,1,'BOOM') {
       print $contatore, "\n"; sleep(1);
    }
    for (1..15) { print "Buon Natale\n"; }
    foreach $elemento (split(/:[\\\n:]*/, $ENV{TERMCAP})) {
       print "Elemento: $elemento\n";
    }

Ecco come un programmatore C potrebbe scrivere un particolare algoritmo in Perl:

    for (my $i = 0; $i < @ary1; $i++) {
       for (my $j = 0; $j < @ary2; $j++) {
          if ($ary1[$i] > $ary2[$j]) {
               last; # non si puo` andare su quello esterno :-(
          }
          $ary1[$i] += $ary2[$j];
       }
       # ecco dove mi porta quel last
    }

Ecco invece come potrebbe farlo un programmatore Perl più a suo agio con l'idioma:

    ESTERNO: for my $wid (@ary1) {
    INTERNO:   for my $jet (@ary2) {
          next ESTERNO if $wid > $jet;
          $wid += $jet;
       }
    }

Vedete quant'è più facile? È più pulito, sicuro e veloce. È più pulito perché ha meno rumore. È più sicuro perché se più tardi si aggiunge codice fra il ciclo interno e quello esterno, il nuovo codice non verrà eseguito accidentalmente. Il next itera esplicitamente il ciclo esterno invece che ridursi a terminare quello interno. Ed è più veloce perché Perl esegue un'istruzione foreach più rapidamente di quanto farebbe un ciclo for equivalente.

BLOCCHI base ed Istruzioni Switch

Un BLOCCO di per sé (etichettato o meno) è semanticamente equivalente ad un ciclo che viene eseguito una volta. Per questo motivo potete utilizzare una qualunque delle istruzioni di controllo di ciclo al suo interno, per lasciare o far ripartire il blocco. (Osservate che ciò NON vale per eval{} e sub{}, o contrariamente al credo popolare per i blocchi do{}, che NON contano come cicli). Il blocco continue è opzionale.

Il costrutto BLOCCO è particolarmente utile per realizzare strutture case [istruzione C che marca una fra più parti di codice differenti a seconda del valore di un'espressione, NdT].

    SWITCH: {
       if (/^abc/) { $abc = 1; last SWITCH; }
       if (/^def/) { $def = 1; last SWITCH; }
       if (/^xyz/) { $xyz = 1; last SWITCH; }
       $niente = 1;
    }

Non esite alcuna istruzione switch ufficiale in Perl, perché ci sono già molti modi per scrivere qualcosa di equivalente.

Ad ogni modo, a partire da Perl 5.8, per avere switch e case si può utilizzare l'estensione Switch e dichiarare:

        use Switch;

dopo di che si hanno switch e case. Non è veloce come potrebbe perché non è veramente parte del linguaggio (è realizzato utilizzando dei filtri sul codice sorgente), ma è disponibile e molto flessibile.

In aggiunta al costrutto BLOCCO citato, potreste anche scrivere

    SWITCH: {
       $abc = 1, last SWITCH  if /^abc/;
       $def = 1, last SWITCH  if /^def/;
       $xyz = 1, last SWITCH  if /^xyz/;
       $niente = 1;
    }

(Non è, in realtà, strano come sembra una volta compreso che potete utilizzare ``operatori'' di controllo del ciclo all'interno di un'espressione. Si sta solo utilizzando l'operatore binario ``virgola'' in contesto scalare. Consultate perlop/``Comma Operator'' [``L'operatore virgola'', NdT]).

o

    SWITCH: {
       /^abc/ && do { $abc = 1; last SWITCH; };
       /^def/ && do { $def = 1; last SWITCH; };
       /^xyz/ && do { $xyz = 1; last SWITCH; };
       $niente = 1;
    }

o formattato in modo che risalti di più come un'istruzione switch ``propria'':

    SWITCH: {
       /^abc/       && do {
                    $abc = 1;
                    last SWITCH;
               };
       /^def/       && do {
                    $def = 1;
                    last SWITCH;
               };
       /^xyz/       && do {
                    $xyz = 1;
                    last SWITCH;
                };
       $niente = 1;
    }

o

    SWITCH: {
       /^abc/ and $abc = 1, last SWITCH;
       /^def/ and $def = 1, last SWITCH;
       /^xyz/ and $xyz = 1, last SWITCH;
       $niente = 1;
    }

o anche, orrore,

    if (/^abc/)
       { $abc = 1 }
    elsif (/^def/)
       { $def = 1 }
    elsif (/^xyz/)
       { $xyz = 1 }
    else
       { $niente = 1 }

Un idioma comune per un'istruzione switch consiste nell'utilizzare l'aliasing di foreach per effetture assegnazioni temporanee a $_ ed ottenere un matching conveniente:

    SWITCH: for ($dove) {
        /Nei Nomi delle Carte/  && do { push @flags, '-e'; last; };
        /Ovunque/               && do { push @flags, '-h'; last; };
        /Nelle Regole/          && do {                    last; };
        die "valore sconosciuto per la variabile dove: `$dove'";
      }

Un altro approccio interessante per un'istruzione switch consiste nel fare in modo che un blocco do restituisca il valore corretto:

    $amode = do {
       if     ($flag & O_RDONLY) { "r" }        # XXX: non e` 0?
       elsif  ($flag & O_WRONLY) { ($flag & O_APPEND) ? "a" : "w" }
       elsif  ($flag & O_RDWR)   {
           if ($flag & O_CREAT)  { "w+" }
           else                  { ($flag & O_APPEND) ? "a+" : "r+" }
       }
    };

O

        print do {
            ($flags & O_WRONLY) ? "write-only"          :
            ($flags & O_RDWR)   ? "read-write"          :
                                  "read-only";
        };

O se siete certi che tutte le clausole in && sono vere, potete utilizzare qualcosa come quello che segue, che ``cambia'' in base al valore della variabile di ambiente HTTP_USER_AGENT.

    #!/usr/bin/perl 
    # prendi la pagina del file jargon in base al browser
    $dir = 'http://www.wins.uva.nl/~mes/jargon';
    for ($ENV{HTTP_USER_AGENT}) { 
       $page  =     /Mac/            && 'm/Macintrash.html'
                 || /Win(dows )?NT/  && 'e/evilandrude.html'
                 || /Win|MSIE|WebTV/ && 'm/MicroslothWindows.html'
                 || /Linux/          && 'l/Linux.html'
                 || /HP-UX/          && 'h/HP-SUX.html'
                 || /SunOS/          && 's/ScumOS.html'
                 ||                     'a/AppendixB.html';
    }
    print "Location: $dir/$page\015\012\015\012";

Questo tipo di istruzione switch funziona solamente quando sapete che le clausole && saranno vere. Se non siete sicuri, dovreste affidarvi all'esempio precedente con ?:.

Potreste anche prendere in considerazione lo scrivere una hash contenente riferimenti a subroutine invece di realizzare un'instruzione switch.

Goto

Sebbene non sia adatta ai deboli di cuore, Perl supporta un'istruzione goto. Esiste in tre forme: goto-ETICHETTA, goto-ESPRESSIONE e goto-&NOME. Un'etichetta di ciclo non costituisce, in realtà, un valido obiettivo per una goto; è solo il nome del ciclo.

La forma goto-ETICHETTA trova l'istruzione etichettata con ETICHETTA e riprende l'esecuzione da lì. Non può essere utilizzata per andare in un qualunque costrutto che richieda inizializzazione, come una subroutine o un ciclo foreach. Non può nemmeno essere utilizzata per andare in un costrutto che viene ottimizzato. Può invece essere usata per andare praticamente in qualsiasi posto che si trovi nello scope dinamico, inclusa l'uscita dalle subroutine. Ma di solito è meglio utilizzare altri costrutti come last o die. L'autore di Perl non ha mai sentito il bisogno di utilizzare questa forma di goto (in Perl perlomeno -- in C è un'altra storia).

La forma goto-ESPRESSIONE si aspetta il nome di un'etichetta, il cui scope verrà risolto dinamicamente. Questo consente di avere dei goto calcolati come in FORTRAN, ma non è nesessariamente raccomandato se cercate di ottimizzare il codice rispetto alla manutenibilità:

    goto(("PIPPO", "PLUTO", "TOPOLINO")[$i]);

La forma goto-&NOME è estremamente magica, e sostituisce una chiamata alla subroutine nominata al posto della subroutine attualmente in esecuzione. Questo meccanismo viene utilizzato dalle subroutine AUTOLOAD() che vogliono caricare un'altra subroutine e far finta che tale altra subroutine sia stata chiamata sin dall'inizio (eccetto che eventuali modifiche a @_ nella subroutine corrente siano propagate anche nell'altra). Dopo una goto, nemmeno caller() sarà in grado di dire che questa routine è stata chiamata prima.

In quasi tutti i casi come questo, è di solito un'idea di gran lunga migliore utilizzare i meccanismi di controllo di flusso dati da next, last o redo piuttosto che abbassarsi al livello di goto. Per certe applicazioni, la coppia di catch e throw [terminologia utilizzata per parlare della gestione delle eccezioni in molti linguaggi, fra cui C++ e Java, NdT] fornita da eval{} e die() per l'elaborazione delle eccezioni può risultare un approccio prudente.

POD: Documentazione Immersa

Perl ha un meccanismo per inframmezzare la documentazione con il codice sorgente. Nei punti in cui si aspetta l'inizio di una nuova istruzione, se il compilatore incontra una riga che comincia con un segno uguale ed una parola, come questa:

    =head1 Ecco che arrivano i Pod!

allora il testo nella riga e tutto quello che segue fino ad una riga che comincia con =cut (riga compresa) sarà ignorato. Il formato del testo incluso è descritto in perlpod.

Ciò vi consente di inframmezzare liberamente codice e documentazione, come in

    =item spippola($)
    La funzione spippola() si comportera` nella piu` spettacolare
    delle forme che possiate mai immaginare, senza nemmeno escludere
    forme pirotecniche cibernetiche.
    =cut torniamo al compilatore, niente di questa roba pod!
    sub spippola($) {
       my $cosetta = shift;
       # .........
    }

Osservate che i traduttori pod dovrebbero guardare solo ai paragrafi che iniziano con una direttiva pod (rende più semplice il parsing), laddove il compilatore di fatto sa rilevare delle eccezioni pod anche nel bel mezzo di un paragrafo. Questo signifca che la roba segreta che segue verrà ignorata sia dal compilatore che dai traduttori.

    $a=3;
    =roba segreta
     warn "Ne' CODICE ne' POD!?"
    =cut indietro
    print "preso $a\n";

Probabilmente, però, non dovreste contare troppo sul fatto che l'istruzione warn() qui sopra verrà eliminata come pod per sempre. Non tutti i traduttori di pod si comportano bene a questo proposito, e forse il compilatore diverrà più bizzoso.

Si possono anche utilizzare le direttive pod per commentare rapidamente una sezione di codice.

Buoni Vecchi Commenti (No!)

Perl può elaborare direttive di riga, molto similmente al preprocessore C. Utilizzando questo meccanismo, è possibile controllare l'idea che Perl ha dei nomi dei file e dei numeri di riga nei messaggi di errore o di avviso (specialmente per quelle stringhe che sono elaborate con eval()). La sintassi per questo meccanismo è la stessa che per la maggior parte dei preprocessori C: aderisce all'espressione regolare

    # esempio: '# riga 42 "nuovo_nomefile.plx"'
    /^\#   \s*
      line \s+ (\d+)   \s*
      (?:\s("?)([^"]+)\2)? \s*
     $/x

laddove $1 rappresenta il numero di riga per la prossima riga, e $3 rappresenta il nome del file opzionale (specificato con o senza virgolette).

C'è una cosa piuttosto ovvia da cui guardarsi quando si utilizza la direttiva line: i debugger ed i profiler [programmi che analizzano le prestazioni delle varie sezioni del programma, NdT] mostreranno solo l'ultima riga riga sorgente come presente ad un particolare numero di riga in un dato file. Dovete prestare attenzione a non generare delle collisioni nei numeri di riga nel codice su cui avrete poi voglia di effettuare il debug.

Ecco alcuni esempi che dovreste essere in grado di digitare nella vostra shell di comando:

    % perl
    # line 200 "bzzzt"
    # il `#' nella riga precedente deve essere il primo carattere nella riga
    die 'pippo';
    __END__
    pippo at bzzzt line 201.
    % perl
    # line 200 "bzzzt"
    eval qq[\n#line 2001 ""\ndie 'pippo']; print $@;
    __END__
    pippo at - line 2001.
    % perl
    eval qq[\n#line 200 "pippo pluto"\ndie 'pippo']; print $@;
    __END__
    pippo at pippo pluto line 200.
    % perl
    # line 345 "miao"
    eval "\n#riga " . __LINE__ . ' "' . __FILE__ ."\"\ndie 'pippo'";
    print $@;
    __END__
    pippo at miao line 345.


TRADUZIONE

Versione

La versione su cui si basa questa traduzione è ottenibile con:

   perl -MPOD2::IT -e print_pod perlsyn

Per maggiori informazioni sul progetto di traduzione in italiano si veda http://pod2it.sourceforge.net/ .

Traduttore

Traduzione a cura di kral e Flavio Poletti.

Revisore

Revisione a cura di dree.


Mon Jun 11 22:02:19 2012