perlmod - moduli Perl (pacchetti e tabelle dei simboli)
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.].
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).
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__
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.
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.
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 .
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.
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/ .
Traduzione a cura di Flavio Poletti.
Revisione a cura di dree.
Mon Jun 11 22:02:17 2012
|