La Filosofia Perl

Perl risolve problemi—è flessibile, accomodante e malleabile. Programmatori in gamba lo usano ogni giorno per i compiti più diversi, dai programmi di automazione ad hoc lunghi una riga ai progetti che coinvolgono molti programmatori e durano anni.

Perl è pragmatico, e il controllo è in mano al programmatore. Siete voi a scegliere come risolvere un problema, e Perl asseconderà le vostre intenzioni senza darvi fastidio e senza tante cerimonie.

Perl è un linguaggio che cresce di pari passo con le vostra conoscenze. Nel giro di un'ora imparerete abbastanza per poter scrivere dei programmi utili a risolvere problemi reali—e imparerete come funziona il linguaggio e perché funziona in quel modo. A partire da questa conoscenza e dalla esperienza della comunità Perl mondiale, Perl Moderno ci aiuterà a scrivere codice che funziona ed è facilmente manutenibile.

Prima di tutto, avete bisogno di sapere come imparare di più.

Perldoc

Una buona documentazione fa parte della cultura Perl. L'utility perldoc fa parte di qualunque installazione completa di Perl 5 Il vostro sistema Unix-like potrebbe richiedere l'installazione di un pacchetto aggiuntivo come perl-doc su Debian o Ubuntu GNU/Linux.. perldoc visualizza la documentazione di qualsiasi modulo Perl installato sul sistema—sia che sia integrato nella distribuzione sia che sia stato installato dal Comprehensive Perl Archive Network (CPAN)—oltre alle migliaia di pagine della ampia documentazione di base di Perl.

Usate perldoc per leggere la documentazione di un modulo o una parte della documentazione di base:

    $ perldoc List::Util
    $ perldoc perltoc
    $ perldoc Moose::Manual

Il primo esempio mostra la documentazione presente all'interno nel modulo List::Util. Il secondo esempio mostra un file di sola documentazione, in questo caso l'indice della documentazione di base. Il terzo esempio mostra un file di sola documentazione incluso come parte di una distribuzione su CPAN (Moose). perldoc permette di ignorare questi dettagli; non c'è infatti differenza tra leggere la documentazione di una libreria integrata, come Data::Dumper, o di una installata da CPAN.

La struttura standard per la documentazione include una descrizione del modulo, mostra dei semplici esempi di uso, e prosegue con una spiegazione dettagliata del modulo e della sua interfaccia. Mentre il livello di dettaglio della documentazione varia da un autore all'altro, il suo formato presenta una notevole uniformità.

Come Leggere la Documentazione

perldoc perltoc mostra l'indice della documentazione di base, e perldoc perlfaq mostra l'indice delle domande frequenti (Frequently Asked Questions) su Perl 5. perldoc perlop e perldoc perlsyn documentano gli operatori e i costrutti sintattici di Perl. perldoc perldiag spiega il significato dei messaggi di avvertenza. perldoc perlvar elenca tutte le variabili simboliche. Dare un'occhiata a questi file è utilissimo per farvi un'idea generale di Perl 5.

L'utility perldoc ha molte altre funzionalità (vedete perldoc perldoc). L'opzione -q cerca i termini che le vengono forniti nelle FAQ del Perl. Per esempio, perldoc -q sort restituisce tre domande frequenti: How do I sort an array by (anything)?, How do I sort a hash (optionally by value instead of key)? e How can I always keep my hash sorted?.

L'opzione -f mostra la documentazione di una funzione predefinita di Perl, ad esempio perldoc -f sort spiega il funzionamento dell'operatore sort. Se non sapete il nome della funzione che vi serve, scorrete la lista di funzioni predefinite in perldoc perlfunc.

L'opzione -v cerca la documentazione su una variabile predefinita. Per esempio, perldoc -v $PID mostra la documentazione sulla variabile che contiene l'id del processo del programma in esecuzione. A seconda della shell che usate, potreste dover quotare opportunamente il nome della variabile.

Con l'opzione -l, perldoc mostra il percorso del file di documentazione anziché il suo contenuto Tenete presente che un modulo potrebbe avere un file .pod separato dal file .pm..

L'opzione -m mostra l'intero contenuto di un modulo, codice incluso, senza effettuare alcuna formattazione particolare.

Il sistema di documentazione di Perl 5 è POD (Plain Old Documentation). perldoc perlpod descrive come funziona POD. Altri tool relativi a POD sono podchecker, che controlla la validità di un documento POD, e Pod::Webserver, che mostra i POD locali in formato HTML con un web server minimale.

Espressività

Gli studi di linguistica e lingue umane di Larry Wall hanno molto influenzato la progettazione di Perl. Come conseguenza, il linguaggio vi dà una enorme libertà nel modo di risolvere i problemi, a seconda dello stile del vostro gruppo di lavoro, del tempo a vostra disposizione, quanto a lungo il programma dovrà continuare a funzionare, e persino di quanto vi sentite creativi. Potete scrivere un pezzo di codice semplice e lineare oppure partecipare alla scrittura di programmi di grandi dimensioni, basati su un progetto ben definito. Potete scegliere tra diversi paradigmi di programmazione, e decidere di evitare o di adottare le funzionalità più avanzate.

Laddove altri linguaggi impongono un singolo modo "corretto" di scrivere ciascun pezzo di codice, Perl lascia a voi decidere che cosa è più leggibile, efficace o semplicemente divertente.

I programmatori Perl hanno uno slogan per questo: TIMTOWTDI, pronunciato "Tim Toady", ovvero "There's more than one way to do it!" ("C'è più di un modo per farlo!").

Questa espressività permette ai maestri del linguaggio di creare programmi superlativi, ma permette anche ai neofiti e ai programmatori poco accorti di fare pasticci. L'esperienza e il gusto estetico vi guideranno a scrivere codice eccellente. La scelta è vostra—ma prestate attenzione alla leggibilità e alla manutenibilità, specialmente per chi verrà dopo di voi.

I principianti di Perl spesso trovano che alcuni dei suoi costrutti siano poco comprensibili. Molti di questi idiomi (Idiomi) sono estremamente potenti, anche se in modi sottili e non sempre ovvi. Può essere una buona idea evitarli fino a che non arrivate a padroneggiarli.

Imparare Perl è come imparare una nuova lingua. Imparerete alcune parole, metterete insieme delle frasi, e presto potrete sostenere semplici conversazioni. La padronanza del linguaggio si ottiene esercitandosi sia nella lettura sia nella scrittura. Non dovete conoscere ogni dettaglio di Perl per usarlo in modo produttivo, ma i principi esposti in questo capitolo sono fondamentali per la vostra crescita come programmatori.

Un altro degli obiettivi nel progettare Perl è quello di evitare di sorprendere i programmatori (Perl) esperti. Per esempio, sommare due variabili ($first_num + $second_num) è ovviamente una operazione numerica (Operatori Numerici); l'operatore di addizione tratta entrambe le variabili come valori numerici e produce un risultato numerico. Indipendentemente da quale sia il contenuto di $first_num e $second_num, Perl li converte in valori numerici (Coercizione Numerica). In altre parole, se avete espresso l'intenzione di trattarli come numeri usando un operatore numerico Perl sarà felice di accontentarvi.

Gli adepti di Perl spesso chiamano questo principo DWIM, ovvero do what I mean (fai ciò che intendo). Un altro modo per dirlo è che Perl segue il principio di minima sorpresa. Data una conoscenza anche solo superficiale di Perl (e specialmente del contesto; Contesto), dovreste riuscire a comprendere lo scopo anche di espressioni Perl che non vi sono familiari. Svilupperete man mano questa capacità.

L'espressività del Perl permette anche ai principianti di scrivere programmi utili senza dover conoscere l'intero linguaggio. Il codice che ne risulta è spesso chiamato baby Perl, nel senso che quasi tutti desiderano aiutare un bambino a imparare a comunicare bene. Tutti noi iniziamo come principianti. Con la pratica e gli insegnamenti dei programmatori più esperti, inizierete a capire e ad adottare gli idiomi e le tecniche più potenti.

Per esempio, un programmatore Perl esperto potrebbe triplicare tutti i numeri di una lista con:

    my @triplicati = map { $_ * 3 } @numeri;

... e un adepto potrebbe scrivere:

    my @triplicati;

    for my $num (@numeri)
    {
        push @triplicati, $num * 3;
    }

... mentre un principiante potrebbe provare con:

    my @triplicati;
    my $cont = @numeri;

    for (my $i = 0; $i < $cont; $i++)
    {
        $triplicati[$i] = $numeri[$i] * 3;
    }

Tutti e tre gli approcci portano allo stesso risultato, ma ciascuno usa Perl in modo diverso.

L'esperienza con la programmazione in Perl vi aiuterà a focalizzarvi sul che cosa volete ottenere piuttosto che sul come ottenerlo. In ogni caso, Perl esegue di buon grado anche i programmi più semplici. Potete progettare e raffinare i vostri programmi per aumentarne la chiarezza, l'espressività, il riutilizzo e la manutenibilità, in parte o completamente. Sfruttate la flessibilità e il pragmatismo: è molto meglio raggiungere il vostro scopo adesso in modo efficace che scrivere un programma di superba purezza e bellezza concettuale l'anno prossimo.

Contesto

In un linguaggio parlato, il significato di una parola o frase può dipendere dal modo in cui viene usata; il contesto aiuta a chiarirne il senso. Per esempio, l'errato uso del plurale in "Vorrei un panini, per favore!" Il plurale del nome è in disaccordo con la quantità. suona subito sbagliato, proprio come l'errore di genere in "la gatto" L'articolo è femminile, mentre il nome è maschile.. Considerate anche il pronome "che" o il nome "città" che possono essere singolari o plurali a seconda del contesto.

Il contesto in Perl è qualcosa di simile. Esso determina quanti e quali dati usare. Perl fa del suo meglio per darvi esattamente quello che chiedete—a patto che lo chiediate utilizzando il contesto appropriato.

Alcune operazioni in Perl hanno un diverso comportamento a seconda che vogliate ottenere da loro zero, uno o più di un risultato. Un costrutto Perl può fare due cose diverse se scrivete "Fai questo, ma non mi importa del risultato" piuttosto che "Fai questo, e mi aspetto più di un risultato". Altre operazioni vi permettono di specificare se intendete lavorare con dati numerici, testuali, oppure valori logici vero e falso.

Il contesto può causare confusione se tentate di scrivere o leggere del codice Perl come una sequenza di singole espressioni avulse da ciò che le circonda. Potrà succedervi di volervi dare una botta in testa dopo una lunga sessione di debugging quando finalmente scoprite che l'errore era nelle vostre assunzioni sul contesto. Se invece tenete sempre a mente il contesto, il vostro codice sarà più corretto—oltre che pulito, flessibile e conciso.

Contesti Void, Scalare e Lista

Il contesto di quantità determina quanti elementi vi aspettate da un'operazione. È qualcosa di simile alla concordanza di numero tra soggetto e verbo in italiano. Anche senza conoscere formalmente questo principio, non avete probabilmente problemi a trovare l'errore nella frase "Perl sono un linguaggio divertente". In Perl, il numero di elementi che vi aspettate determina quanti ne otterrete.

Supponete di avere una funzione (Dichiarazione di Funzioni) con nome cerca_faccende() che ordina la vostra lista di faccende di casa da sbrigare in base alla loro priorità. Il modo in cui chiamate questa funzione determina cosa essa produrrà. Potreste non avere tempo di occuparvi di nulla, e in questo caso chiamare la funzione serve solo a far finta di lavorare. Potreste avere abbastanza tempo per fare un lavoro, oppure avere molte energie in un weekend libero e desiderare di sbrigare più faccende possibile.

Se chiamate la funzione senza chiedere un valore di ritorno, la chiamata viene fatta nel contesto void:

    cerca_faccende();

Se assegnate il valore restituito della funzione a un singolo elemento (Scalari), la funzione viene valutata in contesto scalare:

    my $risultato_singolo = cerca_faccende();

Se assegnate il risultato della chiamata ad un array (Array) o a una lista, o lo utilizzate in una lista, la funzione viene valutata in contesto lista:

    my @tutti_i_risultati          = cerca_faccende();
    my ($elemento_singolo, @altri) = cerca_faccende();
    elabora_lista_di_risultati( cerca_faccende() );

Le parentesi nella seconda linea dell'esempio precedente raggruppano le due dichiarazioni di variabli (Scope Lessicale), e l'assegnamento si comporta come vi aspettate. Se si volesse ignorare @altri, potreste scrivere:

    my ($elemento_singolo)   = cerca_faccende();

.... nel qual caso le parentesi suggeriscono al parser di Perl 5 che intendete fare l'assegnamento in contesto lista anche se vi interessa assegnarne solo un elemento. Tutto questo non è forse così ovvio, ma ora che lo sapete, la differenza di quantità tra queste due istruzioni dovrebbe esservi evidente:

    my $contesto_scalare = cerca_faccende();
    my ($contesto_lista) = cerca_faccende();

Valutare una funzione o un'espressione in contesto lista—tranne che negli assegnamenti—può creare qualche confusione. Le liste propagano il contesto lista alle espressioni al loro interno, quindi entrambe queste chiamate a cerca_faccende() sono valutate in contesto lista:

    elabora_lista_di_risultati( cerca_faccende() );

    my %risultati =
    (
        operazione_poco_costosa => $risultati_poco_costosi,
        operazione_costosa       => cerca_faccende(), # OPS!
    );

Quest'ultimo esempio sorprende spesso i programmatori principianti, dato che inizializzare un hash (Hash) con una lista di valori impone un contesto lista alla chiamata a cerca_faccende. Per imporre esplicitamente un contesto scalare, usate l'operatore scalar:

    my %risultati =
    (
        operazione_poco_costosa => $risultati_poco_costosi,
        operazione_costosa      => scalar cerca_faccende(),
    );

Perché è importante il contesto? Una funzione può esaminare il contesto in cui è stata chiamata e decidere di conseguenza quanto lavoro deve fare. In contesto void, cerca_faccende() potrebbe non fare assolutamente nulla. In contesto scalare, deve trovare soltanto il compito più importante. In contesto lista, deve ordinare e restituire l'intera lista di faccende da sbrigare.

Contesti Numerico, Stringa e Booleano

L'altro contesto di Perl—il contesto di valore—determina come Perl interpreta un dato. Probabilmente avrete già notato la flessibilità del Perl nell'indovinare se un dato è un numero o una stringa, e nel convertire tra i due a seconda delle vostre intenzioni. In cambio della possibilità di non dover dichiarare (o quanto meno tener traccia) esplicitamente del tipo di un dato contenuto in una variable o restituito da una funzione, i contesti di valore di Perl forniscono importanti suggerimenti al compilatore su come gestire tali dati.

Perl converte i valori al tipo specifico appropriato (Coercizione), in base agli operatori che usate. Per esempio, l'operatore eq determina se due stringhe contengono la stessa informazione come stringhe:

    say "Errore catastrofico di crittografia!" if $alice eq $bob;

Forse vi è capitato di essere spiacevolmente sorpresi in casi in cui siete sicuri che le stringhe siano diverse, ma confrontandole risultano uguali:

    my $alice = 'alice';
    say "Errore catastrofico di crittografia!" if $alice == 'Bob';

L'operatore eq tratta i suoi operandi come stringhe forzando il contesto stringa su di essi. Invece, l'operatore == impone il contesto numerico. In contesto numerico, entrambe le stringhe vengono valutate come 0 (Coercizione Numerica). Fate attenzione ad usare l'operatore appropriato al tipo di contesto desiderato.

Il contesto Booleano si ha quando usate un valore in una istruzione condizionale. Negli esempi precedenti, if valutava il risultato degli operatori eq e == in contesto booleano.

In rare occasioni, potrebbe essere necessario forzare esplicitamente un contesto se non è possibile trovare un operatore del tipo appropriato. Per forzare un contesto numerico, aggiungete zero ad una variabile. Per forzare un contesto stringa, concatenate la variable con la stringa vuota. Per forzare un contesto booleano, usate due volte l'operatore di negazione:

    my $x_numerico =  0 + $x;  # forza il contesto numerico
    my $x_stringa  = '' . $x;  # forza il contesto stringa
    my $x_booleano =    !!$x;  # forza il contesto booleano

I contesti di tipo sono più facili da identificare rispetto ai contesti di quantità. Una volta che conoscete i contesti forniti dai vari operatori (Tipi di Operatori), è raro che possiate sbagliarvi.

Idee Implicite

Il contesto è solo una delle abbreviazioni linguistiche in Perl. I programmatori che padroneggiano queste abbreviazioni, dando appena un'occhiata al codice, possono capire immediatamente le sue caratteristiche più importanti. Un'altra importante caratteristica linguistica è l'equivalente Perl dei pronomi.

La Variabile Scalare di Default

La variabile scalare di default (detta anche variabile argomento o topic), $_, si nota principalmente per la sua assenza: molte delle operazioni predefinite di Perl lavorano sul contenuto di $_ in assenza di una variabile esplicita. Potete usare $_ come qualunque altra variabile, ma spesso questo risulta superfluo.

Molti degli operatori scalari di Perl (inclusi chr, ord, lc, length, reverse e uc) usano la variabile scalare di default se non gli fornite un'alternativa. Per esempio, la funzione predefinita chomp rimuove una sequenza di "a capo" dalla fine del suo operando Vedete perldoc -f chomp e $/ per maggiori dettagli sul suo comportamento.:

    my $zio = "Roberto\n";
    chomp $zio;
    say "'$zio'";

$_ ha lo stesso ruolo in Perl dei pronomi ciò, quello o del suffisso -lo in italiano. Se non passate esplicitamente una variabile, chomp rimuove la sequenza di "a capo" dalla fine di $_. Perl capisce a che cosa vi riferite quando dite "chomp", e farà sempre "chomp" su "quel" valore. Pertanto, queste due linee di codice sono equivalenti:

    chomp $_;
    chomp;

Analogamente, say e print operano su $_ in assenza di altri argomenti:

    print;  # stampa $_ sul filehandle corrente
    say;    # stampa "$_\n" sul filehandle corrente

Le funzionalità Perl per le espressioni regolari (Espressioni Regolari e Matching) per default usano $_ per i match, le sostituzioni e le traslitterazioni:

    $_ = 'Mi chiamo Paquito';
    say if /Mi chiamo/;

    s/Paquito/Paquita/;

    tr/A-Z/a-z/;
    say;

Le direttive di ciclo del Perl (Direttive di Ciclo) per default usano $_ come variabile su cui iterare. Considerate un ciclo for che itera su una lista:

    say "#$_" for 1 .. 10;

    for (1 .. 10)
    {
        say "#$_";
    }

... oppure il while:

    while (<STDIN>)
    {
        chomp;
        say scalar reverse;
    }

... oppure la trasformazione di una lista con map:

    my @quadrati = map { $_ * $_ } 1 .. 10;
    say for @quadrati;

... o il filtraggio di una lista con grep:

    say 'Colazione!'
        if grep { /fette biscottate/ } @dispensa;

Come una frase in italiano diventa confusa quando usate troppi pronomi e antecedenti, anche in Perl dovete fare attenzione a mescolare usi impliciti o espliciti di $_. Un incauto uso simultaneo di $_ può fare sì che un pezzo di codice sovrascriva tacitamente un valore scritto da un altro pezzo di codice. Se scrivete una funzione che usa $_, potreste interferire con l'uso di $_ da parte del codice che chiama la funzione.

A partire dal Perl 5.10, potete dichiarare $_ come variabile lessicale (Scope Lessicale) per evitare queste interferenze:

    while (<STDIN>)
    {
        chomp;

        # ESEMPIO SBAGLIATO
        my $modificato = calcola_valore( $_ );
        say "Valore originale: $_";
        say "Valore modificato: $modificato";
    }

Se calcola_valore() o qualche altra funzione modifica $_, tale modifica persiste per l'intera iterazione del ciclo. Aggiungendo una dichiarazione my si evita di sporcare un'altra istanza di $_:

    while (my $_ = <STDIN>)
    {
        ...
    }

Naturalmente, usare una variabile lessicale con un nome appropriato può essere altrettanto chiaro, se non di più:

    while (my $linea = <STDIN>)
    {
        ...
    }

Usate $_ come usereste "ciò" o "quello" in un documento formale: occasionalmente, in contesti limitati e ben definiti.

L'operatore ...

Perl 5.12 ha introdotto l'operatore triplo-punto (...) come segnaposto per del codice che volete scrivere successivamente. In fase di parsing, Perl lo tratta come un'istruzione completa, ma solleva un'eccezione al vostro tentativo di eseguire del codice non implementato se tentate di eseguirlo. Vedete perldoc perlop per maggiori dettagli.

Le Variabili Array di Default

Perl fornisce anche due variabili array implicite. Anzitutto, Perl passa gli argomenti alle funzioni (Dichiarazione di Funzioni) in un array di nome @_. Le operazioni di manipolazione di array (Array) all'interno delle funzioni per default lavorano su questo array, per cui i due seguenti frammenti di codice sono equivalenti:

    sub pippo
    {
        my $arg = shift;
        ...
    }

    sub pippo_con_argomenti_espliciti
    {
        my $arg = shift @_;
        ...
    }

Come $_ corrisponde al pronome quello, @_ corrisponde al pronome quelli. Contrariamente a $_, Perl gestisce automaticamente diverse versioni locali di @_ quando chiamate altre funzioni. Gli operatori nativi shift e pop operano su @_ se non fornite altri operandi.

Nel codice esterno alle funzioni, la variabile array di default @ARGV contiene gli argomenti passati al programma dalla linea di comando. Esternamente alle funzioni, le operazioni sugli array (incluse shift e pop) operano implicitamente su @ARGV. Non potete usare @_ se vi serve @ARGV.

readline

L'operatore Perl <$fh> è equivalente alla funzione predefinita readline. readline $fh ha lo stesso effetto di <$fh>. A partire da Perl 5.10, la chiamata readline senza argomenti è equivalente a <>, quindi ora potete usare readline dappertutto. Per ragioni storiche, l'uso di <> è ancora il più diffuso, ma siete invitati a prendere in considerazione l'uso di readline per la sua maggiore leggibilità. Probabilmente preferite glob '*.html' a <*.html>, giusto? Ecco, l'idea è la stessa.

C'è un caso speciale che riguarda ARGV. Se leggete dal filehandle nullo <>, Perl tratterà ciascun elemento di @ARGV come se fosse il nome di un file da aprire in lettura. (Se @ARGV è vuoto, Perl leggerà da standard input). Questo uso implicito di @ARGV è utile per scrivere programmi brevi, come questo filtro a linea di comando che rovescia il suo input:

    while (<>)
    {
        chomp;
        say scalar reverse;
    }

Perché quello scalar? say impone un contesto lista ai suoi operandi. reverse propaga il proprio contesto ai suoi operandi, trattandoli come lista in contesto lista e come una stringa concatenata in contesto scalare. Se il comportamento di reverse vi suona confuso, non avete torto. Perl 5 avrebbe probabilmente dovuto separare l'inversione di una stringa dall'inversione di una lista.

Se eseguite il codice sopra passando una lista di file:

    $ perl rovescia_linee.pl cifrato/*.txt

... il risultato sarà un lungo testo in output. Se non passate argomenti, potete fornire il vostro standard input con una pipe da un altro programma o scrivendo direttamente sulla tastiera. Ricordatevi comunque che Perl può fare molto di più che scrivere piccoli programmi a linea di comando....