index | project | pods | responsabili

NOME

perlmod - moduli Perl (pacchetti e tabelle dei simboli)


DESCRIZIONE

Pacchetti

Perl mette a disposizione un meccanismo in cui spazi dei nomi alternativi fanno in modo che le variabili dei pacchetti non facciano a botte con le altre. Infatti, non esiste qualcosa di esattamente corrispondente ad una variabile globale in Perl. L'istruzione package dichiara che l'unità di compilazione risiede in un dato spazio dei nomi. La visibilità della dichiarazione package va dalla dichiarazione stessa fino alla fine del blocco che la racchiude, eval, o file: la prima che arriva (è lo stesso campo di azione degli operatori my() e local()). Gli identificatori dinamici non qualificati saranno inclusi nello spazio dei nomi, eccetto per quei pochi identificatori che, se non qualificati, appartengono per default al pacchetto main [principale, N.d.T.] invece che a quello corrente, come descritto più avanti. Un'istruzione package ha effetto solo sulle variabili dinamiche -- incluse quelle su cui avete utilizzato local() -- ma non variabili lessicali create con my(). Tipicamente sarebbe la prima dichiarazione in un file incluso da do, require o use. Potete inserirvi in un pacchetto in più di un punto; influisce unicamente su quale tabella dei simboli viene utilizzata dal compilatore per il resto del blocco. Potete riferirvi a variabili e filehandle in altri pacchetti aggiungendo all'identificatore un prefisso, costituito dal nome del pacchetto ed una coppia di due punti: $Pacchetto::Variabile. Se il nome del pacchetto è vuoto si assume il pacchetto main. Ossia, $::naviga è equivalente a $main::naviga.

Il vecchio delimitatore per i pacchetti era un apice singolo, ma la coppia di due punti è ora il delimitatore preferito, in parte perché più leggibile per gli umani, in parte perché è più leggibile dalle macro di emacs. In più fa sentire i programmatori C++ come se sapessero cosa sta succedendo -- contrariamente a quando si utilizza l'apice singolo come separatore, che stava lì per far sentire i programmatori Ada come se sapessero cosa stava succedendo. Poiché la sintassi vecchia maniera è ancora supportata per compatibilità, se provate ad utilizzare una stringa come "Ma $tu'ndo vai", in realtà state accedendo alla variabile $tu::ndo, ossia alla variabile $ndo nel pacchetto tu, il che probabilmente non è quel che intendete. Utilizzate le parentesi graffe per eliminare l'ambiguità, come in "Ma ${tu}'ndo vai".

I pacchetti possono, a loro volta, contenere separatori di pacchetto, come in $ESTERNO::INTERNO::variabile. Ad ogni modo, ciò non implica alcunché nell'ordine della ricerca dei nomi. Non esistono pacchetti relativi: tutti i simboli sono o locali al pacchetto corrente, o devono essere qualificati dal pacchetto più esterno in giù. Ad esempio, nel pacchetto ESTERNO non esiste niente per cui $INTERNO::variabile possa riferirsi a $ESTERNO::INTERNO::variabile. INTERNO si riferisce ad un pacchetto globale completamente separato.

Solo gli identificatori che cominciano con lettere (o underscore [il trattino basso ``_'', N.d.T.] sono registrate nella tabella dei simboli di un pacchetto. Tutti gli altri simboli sono tenuti nel pacchetto main, incluse le variabili con segni di interpunzione, come $_. In aggiunta, quando non qualificati, gli identificatori STDIN, STDOUT, STDERR, ARGV, ARGVOUT, ENV, INC e SIG vengono forzati nel pacchetto main, anche quando utilizzati per altri scopi rispetto a quelli per cui sono stati concepiti. Se avete pacchetti chiamati m, s o y, allora non potete utilizzare la forma qualificata di un identificatore, perché sarebbe interpretata rispettivamente come un pattern match, una sostituzione o una translitterazione.

Le variabili che cominciano con underscore una volta erano forzate all'interno del pacchetto main, ma abbiamo deciso che era meglio, per chi scriveva i pacchetti, il poter utilizzare l'underscore iniziale per indicare variabili e metodi privati. In ogni caso, le variabili e le funzioni chiamate con un singolo _, come $_ e sub _, sono ancora forzate all'interno del pacchetto main. Vedete anche perlvar/``Technical Note on the Syntax of Variable Names'' [Nota Tecnica sulla Sintassi dei Nomi delle Variabili, N.d.T.].

Le stringhe passate ad eval sono compilate all'interno del pacchetto in cui era stata compilata la eval stessa. (Le assegnazioni a $SIG{}, invece, assumono il gestore di segnale specificato nel pacchetto main. Se volete avere un gestore di segnale all'interno di un pacchetto dovete qualificare per intero il nome del gestore). Per un esempio esaminate perldb.pl nella libreria Perl. Inizialmente passa al pacchetto DB, di modo che il debugger non interferisca con le variabili nel programma mentre state cercando di effettuare il debug. In vari punti, comunque, ritorna temporaneamente indietro nel pacchetto main per valutare le varie espressioni nel contesto del pacchetto main (o da qualunque altro posto veniate). Consultate perldebug.

Il simbolo speciale __PACKAGE__ contiene il nome del pacchetto corrente, ma non può essere utilizzato (facilmente) per costruire nomi di variabili.

Consultate perlsub per altre questioni sul campo d'azione relative a my() e local(), e perlref riguardo alle chiusure [closures, N.d.T.].

Tabelle dei Simboli

La tabella dei simboli per un pacchetto viene memorizzata nell'hash con il nome del pacchetto ed una coppia di punto e virgola giustapposti. La tabella dei simboli principale risulta pertanto essere %main::, o anche %:: per brevità. Similmente, la tabella dei simboli per i pacchetti annidati menzionati in precedenza è chiamata %ESTERNO::INTERNO::.

IL valore in ciascun elemento dell'hash è ciò a cui vi riferite quando utilizzate la notazione typeglob *nome. Le seguenti notazioni, infatti, hanno lo stesso effetto, sebbene la prima sia più efficiente perché effettua la ricerca all'interno della tabella dei simboli durante la compilazione:

   local *main::pippo   = *main::pluto;
   local $main::{pippo} = $main::{pluto};

(Siate sicuri di notare la enorme differenza fra la seconda riga qui sopra e local $main::pippo = $main::pluto. La prima sta accedendo all'hash %main::, che è la tabella dei simboli del pacchetto main. La seconda sta semplicemente assegnando lo scalare $pluto nel pacchetto main allo scalare $pippo dello stesso pacchetto).

Potete utilizzare quanto detto per stampare tutte le variabili in un pacchetto, ad esempio. La libreria standard, ma datata, dumpvar.pl ed il modulo CPAN Devel::Symdump si basano proprio su questa caratteristica.

L'assegnazione ad un typeglob effettua un'operazione di identificazione, ossia:

    *pippo = *pluto

fa sì che variabili, subroutine, formati e handle di file e directory accessibili attraverso l'identificatore pluto siano accessibili anche attraverso l'identificatore pippo. Se volete creare come alias solo una particolare variabile o subroutine, assegnate un riferimento:

    *pippo = \$pluto;

Ciò rende $pluto e $pippo la stessa variabile, ma lascia @pluto e @pippo due array distinti. Ingegnoso, eh?

C'è una sottile differenza fra le seguenti istruzioni:

    *pippo = *pluto;
    *pippo = \$pluto;

*pippo = *pluto rende i typeglob stessi sinonimi, mentre *pippo = \$pluto fa sì che la porzione SCALARE di due typeglob distinti si riferisca allo stesso valore scalare. Ciò significa che il seguente codice:

    $pluto = 1;
    *pippo = \$pluto;   # Rende $pippo un alias di $pluto
    {
        local $pluto = 2;  # Modifica ristretta al blocco
        print $pippo;      # Stampa '1'!
    }

stamperebbe '1', perché $pippo mantiene un riferimento a $pluto originale -- quella che è stata nascosta da local() e che sarà ripristinata quando finisce il blocco. Poiché si accede alle variabili attraverso il typeglob, potete utilizzare *pippo = *pluto per creare un alias che può essere localizzato. (State però attenti che ciò significa che non potete avere @pippo e @pluto separate, ecc.).

Quel che rende tutto ciò importante è il fatto che il modulo Exporter utilizza gli alias glob come meccanismo di importazione/esportazione. La possibilità di localizzare in maniera appropriata una variabile che è stata esportata da un modulo dipende dal modo in cui è stata esportata:

    @EXPORT = qw( $pippo );  # Forma abituale, non puo` essere localizzata
    @EXPORT = qw( *pippo );  # Questa si puo` localizzare

Potete aggirare il primo caso utilizzando il nome pienamente qualificato ($Pacchetto::pippo) laddove abbiate bisogno di un valore localizzato, oppure scavalcarlo mettendo *pippo = *Pacchetto::pippo nel vostro script.

Il meccanismo *x = \$y può essere utilizzato per passare (o restituire) riferimenti a buon mercato a (o da) subroutine se non volete effettuare copie. Funziona solo quando assegnate a variabili dinamiche, non a lessicali.

    %una_hash = ();                     # non puo` essere my()
    *una_hash = fn( \%altra_hash );
    sub fn {
       local *hashsym = shift;
       # ora utilizzate %hashsym normalmente, ed andrete
       # a modificare %altra_hash chiamata
       my %nhash = (); # fate cio` che volete
       return \%nhash;
    }

All'uscita dalla funzione, il riferimento sovrascriverà l'elemento per la hash nella tabella dei simboli specificato dal typeglob *una_hash. Questo è un sistema piuttosto ingegnoso per passare riferimenti in maniera economica quando non volete dover effettuare la dereferenziazione esplicita delle variabili.

Un altro utilizzo delle tabelle dei simboli lo si ha per realizzare scalari ``costanti''.

    *PI = \3.14159265358979;

Ora non potete modificare $PI, il che è probabilmente una buona cosa in tutto e per tutto. Ciò non è la stessa cosa di una subroutine costante, la quale è soggetta ad ottimizzazione in fase di compilazione. Una subroutine costante è una subroutine dotata di un prototipo che non prende argomenti in ingresso e che restituisce un'espressione costante. Consultate perlsub per maggiori dettagli a riguardo. L'utilizzo della direttiva use constant è una scorciatoia conveniente per tutto ciò.

Potete dire *pippo{PACKAGE} [pacchetto, ma va posto in inglese quando lo utilizzate, N.d.T.] e *pippo{NAME} [idem, N.d.T.] per trovare quale nome abbia un elemento della tabella dei simboli e da quale pacchetto provenga. Ciò potrebbe essere utile in una subroutine alla quale vengono passati typeglob come argomenti:

    sub identifica_typeglob {
        my $glob = shift;
        print 'Mi hai passato ', *{$glob}{PACKAGE}, '::', *{$glob}{NAME}, "\n";
    }
    identifica_typeglob *pippo;
    identifica_typeglob *pluto::topolino;

Questo stampa

    Mi hai passato main::pippo
    Mi hai passato pluto::topolino

La notazione *pippo{COSA} può essere utilizzata per ottenere riferimenti ai singoli elementi di *pippo. Consultate perlref.

Le definizioni delle subroutine (e le dichiarazione, per quel che importa) non devono essere necessariamente poste nel pacchetto della tabella dei simboli che vanno ad occupare. Potete definire una subroutine al di fuori del suo pacchetto qualificando esplicitamente il nome della subroutine:

    package main;
    sub Un_Pacchetto::pippo { ... }  # &pippo definita in Un_Pacchetto

Questa risulta solo una scorciatoia per un'assegnazione di typeglob in fase di compilazione:

    BEGIN { *Un_Pacchetto::pippo = sub { ... } }

e non è la stessa cosa di:

    {
       package Un_Pacchetto;
       sub pippo { ... }
    }

Nelle prime due versioni il corpo della subroutine risiede lessicalmente nel pacchetto main, non in Un_Pacchetto. Per questo motivo, una cosa tipo:

    package main;
    $Un_Pacchetto::nome = "achille";
    $main::nome = "ulisse";
    sub Un_Pacchetto::pippo {
       print "sono in ", __PACKAGE__, ": \$nome e` '$nome'\n";
    }
    Un_Pacchetto::pippo();

stampa:

    sono in main: $nome e` 'ulisse'

invece che:

    sono in Un_Pacchetto: $nome e` 'achille'

Questa differenza ha anche implicazioni nell'uso del qualificatore SUPER:: (consultate perlobj).

BEGIN, CHECK, INIT e END

Quattro blocchi di codice chiamati in maniera speciale vengono eseguiti all'inizio ed alla fine di un programma Perl in esecuzione: BEGIN, CHECK, INIT e END.

Questi blocchi possono essere preceduti da sub per dare l'illusione di una subroutine (sebbene non sia considerato un gran che come stile). Va notato che questi blocchi di codice non esistono realmente come subroutine aventi un nome (a dispetto della loro apparenza). La loro peculiarità consiste nel fatto che potete avere più d'uno di questi blocchi di codice in un programma, e che questi saranno tutti eseguiti nel momento opportuno. Per questo, non potete eseguire nessuno di essi chiamandoli esplicitamente con il loro nome.

Un blocco BEGIN viene eseguito il prima possibile, ossia nel momento che risulta completamente definito, anche prima che resto del file (o della stringa) sia interpretato. Potete avere più blocchi BEGIN in un file (o in una stringa utilizzata con eval) -- essi saranno eseguiti nello stesso ordine in cui sono stati definiti. Poiché un blocco BEGIN viene eseguito immediatamente, potete inserirvi la definizione di subroutine e cose del genere da altri file in tempo per essere visibili al resto delle fasi di compilazione ed esecuzione. Una volta che BEGIN è stato eseguito, viene immediatamente reso indefinito e qualunque codice e memoria esso abbia utilizzato viene restituito.

Va notato che i blocchi di codice BEGIN sono eseguiti all'interno di eval di stringhe. I blocchi CHECK ed INIT, al contrario, non sono eseguiti all'interno di una eval di stringa, il che può essere un problema in ambiente mod_perl.

Un blocco END viene eseguito il più tardi possibile, ossia dopo che perl ha finito di eseguire il programma ed immediatamente prima che l'interprete sia terminato, anche se si sta uscendo come risultato di una chiamata a die(). (Ma non se ci si sta per trasformare in un altro programma utilizzando exec, o si viene gettati a mare da un segnale -- dovete catturarli da voi, se potete). Potete avere blocchi END multipli all'interno di un file -- verranno eseguiti in ordine inverso di definizione, ossia secondo la regola per cui l'ultimo entrato è il primo ad uscire (LIFO [Last In, First Out, N.d.T.]). I blocchi END non sono eseguiti se state eseguendo perl con l'opzione -c, o se la compilazione non va a buon fine.

Osservate che i blocchi di codice END non sono eseguiti alla fine di una eval() di una stringa: se viene creato un blocco END in una eval() di una stringa, questo sarà eseguito proprio come ogni altro blocco END di quel pacchetto, ossia in ordine LIFO immediatamente prima che l'interprete sia terminato.

All'interno di un blocco END, la variabile $? contiene il valore che il programma sta per passare a exit(). Potete modificare $? per modificare il valore di uscita del programma. Attenzione a non cambiare $? per sbaglio (ad esempio lanciando qualcosa utilizzando system).

I blocchi CHECK e INIT sono utili per cattuare la transizione fra la fase di compilazione e quella di esecuzione nel programma principale.

I blocchi CHECK sono eseguiti immediatamente dopo il termine della fase di compilazione iniziale da parte di Perl, ed immediatamente prima che che inizi la fase di esecuzione vera e propria, in ordine LIFO. I blocchi CHECK sono utilizzati dalla suite di compilazione Perl per salvare lo stato compilato del programma.

I blocchi INIT sono eseguiti immediatamente prima che inizi la fase di runtime, in ordine ``chi prima arriva prima esce'' (FIFO [First In, First Out, N.d.T.]). Ad esempio, i generatori di codice documentati in perlcc fanno uso dei blocchi INIT per inizializzare e risolvere i puntatori alle XSUB.

Quando utilizzate le opzioni -n e -p di Perl, BEGIN e END funzionano proprio come in awk, come caso degenere. Sia BEGIN che CHECK sono eseguiti quando utilizzate l'opzione -c per un controllo della sintassi di tipo meramente compilativo, sebbene il vostro codice non lo sia.

Il seguente programma controlla_begin rende infine tutto chiaro:

  #!/usr/bin/perl
  # controlla_begin
  print         " 8. Codice ordinario a runtime.\n";
  END { print   "14.   Questa e` dunque la fine della favola.\n" }
  INIT { print  " 5. I blocchi INIT sono eseguiti in FIFO appena prima del runtime.\n" }
  CHECK { print " 4.   Questa e` dunque la quarta riga.\n" }
  print         " 9.   Viene eseguita in ordine, chiaramente.\n";
  BEGIN { print " 1. I blocchi BEGIN sono eseguiti in FIFO durante la compilazione.\n" }
  END { print   "13.   Consultate perlmod per il resto della storia.\n" }
  CHECK { print " 3. I blocchi CHECK sono eseguiti in LIFO alla fine della compilazione.\n" }
  INIT { print  " 6.   Provate a rieseguire questo programma con l'opzione -c.\n" }
  print         "10.   Questo e` codice anti-offuscato.\n";
  END { print   "12. I blocchi END sono eseguiti in LIFO al momento di uscire.\n" }
  BEGIN { print " 2.   Questa viene dunque fuori come seconda.\n" }
  INIT { print  " 7.   Vedrete la differenza in quattro e quattr'otto.\n" }
  print         "11.   E` solo che _sembra_ essere confuso.\n";
  __END__

Classi Perl

Non esiste alcuna sintassi speciale per le classi in Perl, ma un pacchetto può comportarsi come una classe se mette a disposizione subroutine che si comportano come metodi. Un tale pacchetto può anche derivare qualcuno dei suoi metodi da un'altra classe (pacchetto) inserendo i nomi degli altri pacchetti nel suo array globale @ISA (che deve essere una variabile globale a livello di pacchetto, un una variabile lessicale).

Per maggiori dettagli consultate perltoot e perlobj.

Moduli Perl

Un modulo è solamente un insieme di funzioni correlate in un file di libreria, ossia un pacchetto Perl con lo stesso nome del file. Viene progettato specificamente per essere riutilizzabile da parte di altri moduli o programmi. Può ottenere questo scopo fornendo un meccanismo per esportare alcuni dei propri simboli nella tabella dei simboli di qualunque pacchetto che lo utilizza, o potrebbe lavorare come una definizione di classe e far sì che la propria semantica sia disponibile implicitamente attraverso chiamate ai metodi sulla classe e sui suoi oggetti, senza esportare niente esplicitamente. O potrebbe fare un po' di tutti e due.

Ad esempio, per iniziare un modulo tradizionale e non orientato agli oggetti chiamato Qualche::Modulo, create un file chiamato Qualche/Modulo.pm e cominciate con questo modello:

    package Qualche::Modulo;  # si assume Qualche/Modulo.pm
    use strict;
    use warnings;
    BEGIN {
        use Exporter   ();
        our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
        # imposta la versione per il controllo della stessa
        $VERSION     = 1.00;
        # se si sta utilizzando RCS/CVS, questa potrebbe essere migliore
        $VERSION = sprintf "%d.%03d", q$Revision: 1.6 $ =~ /(\d+)/g;
        @ISA         = qw(Exporter);
        @EXPORT      = qw(&funz1 &funz2 &funz4);
        %EXPORT_TAGS = ( );     # esempio: TAG => [ qw!nome1 nome2! ],
        # Le vostre variabili globali di pacchetto vanno qui
        # cosi` come qualsiasi funzione esportata opzionalmente
        @EXPORT_OK   = qw($Var1 %Hashit &funz3);
    }
    our @EXPORT_OK;
    # variabili globali di pacchetto esportate vanno qui
    our $Var1;
    our %Hashit;
    # variabili globali di pacchetto non esportate vanno qui
    our @more;
    our $stuff;
    # inizializza le variabili globali di pacchetto, prima quelle esportate
    $Var1   = '';
    %Hashit = ();
    # poi le altre (che sono ancora accessibili attraverso
    # $Qualche::Modulo::roba)
    $roba  = '';
    @altro   = ();
    # Tutte le variabili lessicali limitate al file devono essere
    # create prima delle funzioni piE<ugrave> in basso che le utilizzano
    # Variabili lessicali private per il file vanno qui
    my $priv_var    = '';
    my %hash_segreto = ();
    # Ecco una funzione privata del file implementata come chiusura,
    # chiamabile come &$priv_func; non puE<ograve> essere associata ad un prototipo.
    my $priv_func = sub {
        # la roba va qui.
    };
    # Create le vostre funzioni qui, sia quelle esportate che quelle
    # non esportate. Ricordatevi di inserire qualcosa di interessante
    # nelle parentesi graffe!
    sub funz1      {}    # nessun prototipo
    sub funz2()    {}    # prototipo void [vuoto, N.d.T.]
    sub funz3($$)  {}    # prototipo con due scalari
    # Questa non viene esportata, ma potrebbe essere chiamata!
    sub funz4(\%)  {}    # prototipo con un riferimento ad hash
    END { }       # pulizia del modulo (distruttore globale)
    ## IL VOSTRO CODICE VA QUI
    1;  # non dimenticate di restituire un valore vero dal file

Successivamente andate avanti a dichiarare ed utilizzare le vostre variabili in funzioni senza nessun tipo di qualifica. Consultate Exporter e perlmodlib per maggiori dettagli sulla meccanica e su problematiche di stile relative alla creazione di moduli.

I moduli Perl sono inclusi nel vostro programma dicendo

    use Modulo;

oppure

    use Modulo LISTA;

Ciò equivale esattamente a

    BEGIN { require Modulo; import Modulo; }

ovvero

    BEGIN { require Modulo; import Modulo LISTA; }

Come caso particolare

    use Module ();

è esattamente equivalente a

    BEGIN { require Modulo; }

Tutti i file di modulo Perl condividono l'estensione .pm. L'operatore use assume questa convenzione, così non avete bisogno di scrivere ``Modulo.pm'' fra virgolette. Ciò aiuta a differenziare i moduli nuovi da quelli vecchi con estensione .pl e .ph. I nomi dei moduli sono anche posti con iniziale maiuscola, a meno che non stiano funzionando come direttive; le direttive sono, in effetti, direttive per il compilatore, e sono a volte chiamate ``moduli pragmatici'' (o anche ``pragmata'' se siete classicisti).

Le due istruzioni:

    require QualcheModulo;
    require "QualcheModulo.pm";

differiscono fra loro in due sensi. Nel primo caso, qualunque doppio punto e virgola nel nome del modulo, come in Qualche::Modulo, viene tradotto nel separatore di directory tipico del vostro sistema, solitamente ``/''. Nel secondo caso ciò non è vero, e andrebbe specificato lettera per lettera. L'altra differenza riguarda il fatto che la prima require dà indizi al compilatore che gli utilizzi della notazione indiretta per oggetti che coinvolgono ``QualcheModulo'', così come in $oggetto = ripulisci QualcheModulo, sono in realtà chiamate a metodi, non chiamate a funzione. (Ebbene sì, ciò può fare veramente la differenza).

Poiché l'istruzione use implica un blocco BEGIN, l'importazione delle semantiche avviene non appena l'istruzione stessa viene compilata, prima che sia compilato il resto del file. Questo è il sistema con il quale use è in grado di funzionare come meccanismo di impostazione di direttive, ed anche il modo con cui i moduli sono in grado di dichiarare subroutine che sono poi visibili come operatori di lista o unari per il resto del file corrente. Tutto ciò non funzionerà se utilizzate require invece di use. Con require potete incappare nel seguente problema:

    require Cwd;                # rende Cwd:: accessibile
    $qui = Cwd::getcwd();
    use Cwd;                    # importa i nomi da Cwd::
    $qui = getcwd();
    require Cwd;                # rende Cwd:: accessibile
    $qui = getcwd();            # oops! nessuna subroutine main::getcwd()

In generale, use Modulo () viene raccomandato rispetto a require Modulo, perché determina la disponibilità del modulo nella fase di compilazione, non nel bel mezzo dell'esecuzione del vostro programma. Un'eccezione potrebbe aversi se due moduli provano ciascuno a chiamare use sull'altro, e ciascuno chiama anche una funzione dall'altro modulo. In questo caso, è semplice utilizzare require.

I pacchetti Perl possono essere innestati all'interno di altri nomi di pacchetti, cosicché possiamo avere nomi di pacchetti contenenti ::. Ma se usassimo questi nomi di pacchetti direttamente come nomi di file potremmo avere risultati strani, o impossibili, su alcuni sistemi. Per questo motivo, se il nome di un modulo è, diciamo, Text::Soundex, allora la sua definizione viene in effetti cercata nel file di libreria Text/Soundex.pm.

I moduli Perl hanno sempre un file .pm, ma possono anche esserci eseguibili collegati dinamicamente (spesso questi terminano con .so) o definizioni di subroutine caricate automaticamente (che spesso terminano in .al) associate al modulo. Se questo è il caso, queste saranno comunque completamente trasparenti all'utente del modulo. È responsabilità del file .pm di caricare (o metter su un autoload) qualsiasi funzionalità aggiuntiva. Ad esempio, sebbene il modulo POSIX faccia sia caricamento dinamico che autocaricamento, l'utente può dire semplicemente use POSIX per avere tutto.

Rendere il vostro modulo sicuro per il multithreading

A partire dalla versione 5.6.0 Perl ha supportato un nuovo tipo di thread chiamato thread di interprete (ithreads). Questi thread possono essere utilizzati esplicitamente o implicitamente.

Gli Ithreads lavorano clonando l'albero dei dati cosicché non esistono dati condivisi fra thread differenti. Questi thread possono essere utilizzati mediante il modulo threads oppure chiamando fork() su win32 (con supporto per la fork() finta). Quando un thread viene clonato tutti i dati di Perl sono clonati; in ogni caso, dati non strettamente appartenenti a Perl non possono essere clonati automaticamente. Le versioni successive alla 5.7.2 hanno il supporto per la subroutine speciale CLONE. In questa funzione potete fare qualsiasi cosa riteniate necessaria, come ad esempio gestire la clonazione di dati non relativi a Perl, se necessario. CLONE sarà chiamata un'unica volta come metodo di classe per ciascun pacchetto per cui risulta definita (sia direttamente, sia che la erediti). Verrà chiamata nel contesto del nuovo thread, cosicché tutte le modifiche avranno influsso nella nuova area. Al momento CLONE viene chiamata senza altri parametri se non il nome del pacchetto chiamante, ma il codice non deve fare affidamento sul fatto che questa caratteristica rimarrà invariata, poiché è plausibile che in futuro verranno passati parametri extra per dare maggiore visibilità sullo stato della clonazione.

Se volete utilizzare CLONE su tutti gli oggetti avrete bisogno di tenerne traccia per ciascun pacchetto. Ciò può essere ottenuto semplicemente utilizzando una hash e la funzione Scalar::Util::weaken().

A partire dalla versione 5.8.7, Perl supporta anche la subroutine speciale CLONE_SKIP. Come CLONE, CLONE_SKIP viene chiamata una volta per pacchetto; diversamente, viene chiamata appena prima che parta il processo di clonazione, e nel contesto del thread padre. Se restituisce un valore vero, allora nessun oggetto di quella classe verrà clonato o, piuttosto, verrà copiato come valore indefinito e non associato a nessuna classe. In questo modo viene fornito un meccanismo semplice per rendere un modulo robusto rispetto ai thread; basta aggiungere sub CLONE_SKIP { 1 } all'inizio della classe, e DESTROY() verrà ora chiamata solo una volta per oggetto. Chiaramente, se il thread figlio ha bisogno di utilizzare questi oggetti, è necessario utilizzare un approccio più sofisticato.

Come CLONE, CLONE_SKIP viene oggi come oggi chiamata senza altri parametri se non il pacchetto che la sta chiamando, sebbene questo possa cambiare. In maniera simile, per consentire espansioni future, il valore di ritorno dovrebbe essere un singolo valore fra 0 e 1.


VEDETE ANCHE

Consultate perlmodlib per questioni generali di stile relative alla realizzazione di moduli e classi Perl, così come per trovare descrizioni della libreria standard e CPAN; Exporter per sapere come lavora il meccanismo standard di Perl per importare/esportare i simboli; perltoot e perltooc per un tutorial approfondito sulla creazione di classi; perlobj per trovare un documento di riferimento spinto sugli oggetti; perlsub per una spiegazione delle funzioni e del campo d'azione. Infine, consultate perlxstut e perlguts per maggiori informazioni su come scrivere moduli di estensione.


TRADUZIONE

Versione

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

   perl -MPOD2::IT -e print_pod perlmod

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

Traduttore

Traduzione a cura di Flavio Poletti.

Revisore

Revisione a cura di dree.


Mon Jun 11 22:02:17 2012