Versione stampabile.
|
Mark Jason Dominus  Coping with Scoping |
Traduzione di Stefano Rodighiero
Testo originale: http://perl.plover.com/FAQs/Namespaces.html.
Data di pubblicazione: 06/07/2003.
© Copyright 1998 The Perl Journal. Reprinted with permission. |
| 1. Lo scopo dello scope 2. Variabili package 3. Il package corrente 4. Curiosità sulle variabili package 5. Variabili lessicali 6. local e my 7. A cosa serve local? | 8. Quando usare my e quando usare local 9. Altre proprietà delle variabili my 10. Curiosità su my 11. Dichiarazioni 12. Riassunto 13. Glossario 14. Note |
| Lo scopo dello scope |
All'inizio, in un periodo intorno al 1960, ogni parte del vostro
programma aveva accesso a tutte le variabili presenti in qualsiasi
altra parte del programma. Questo si rivelò un problema, così i
progettisti di linguaggi inventarono le variabili locali, che erano
visibili soltanto in piccole porzioni del programma. In questo modo, i
programmatori che usavano una variabile x potevano essere sicuri che
nessuno sarebbe stato in grado di alterare i contenuti di x
a loro insaputa. Potevano inoltre essere sicuri che usando x non
avrebbero alterato per sbaglio la variabile di qualcun altro.
Ogni linguaggio di programmazione ha una filosofia, e di questi tempi
molte di queste filosofie hanno a che fare con il modo in cui vengono
gestiti i nomi delle variabili. Dettagli come quali variabili sono
visibili in quali parti del programma, e quali nomi vogliano dire
cosa, e quando, sono di primaria importanza. I dettagli variano dal
quasi barocco, in linguaggi come il Lisp, all'estremamente barocco,
in linguaggi quali il C++. Il Perl sfortunatamente cade in qualche punto
all'estremità rococò di questa scala.
Il problema del Perl non è la mancanza di un sistema di gestione dei
nomi chiaramente definito, bensì la presenza di due di questi sistemi,
che lavorano simultaneamente. Ecco il Grande Segreto a proposito delle
variabili in Perl, che la gente impara troppo tardi: il Perl ha due
insiemi di variabili completamente separati e indipendenti. Uno è un'eredità
di Perl 4, e l'altro è nuovo. I due insiemi vengono chiamati
'variabili package' e 'variabili lessicali', e non hanno niente
a che fare l'uno con l'altro.
Poiché sono nate prima, parleremo innanzitutto delle variabili package.
Poi vedremo alcuni problemi ad esse legati, e come le
variabili lessicali siano state introdotte in Perl 5 per evitarli.
Infine, vedremo come fare in modo che il Perl diagnostichi
automaticamente i punti in cui potreste non ottenere la variabile che
volete, e come questo possa rilevare errori prima che essi diventino
bug. |
↑ Variabili package |
$x = 1
Qui, $x è una variabile package. Ci sono due cosa importanti da sapere
a proposito delle variabili package:
-
La variabili package sono quello che ottenete se non specificate diversamente.
-
Le variabili package sono sempre globali.
Globali significa che le variabili package sono sempre visibili
in qualunque punto di qualunque programma. Dopo aver detto $x = 1,
qualunque altra parte del programma, anche un'altra subroutine
definita in un altro file, può ispezionare e modificare il valore
di $x. Non ci sono eccezioni; le variabili package sono sempre
globali.
Le variabili package sono suddivise in famiglie chiamate package.
Ogni variabile package ha un nome diviso in due parti. Tali parti
sono analoghe al nome proprio e al cognome della variabile. Potete chiamare
il Vice-Presidente degli Stati Uniti 'Al', se volete, ma si tratta di
una considerevole abbreviazione del suo nome completo, che è 'Al Gore'egrave;.
Analogamente, $x ha un nome completo, che è qualcosa come $main::x.
La parte main è il qualificatore di package, analogo a 'Gore' in
'Al Gore'.
Al Gore e Al Capone sono persone diverse anche se entrambe sono chiamate
'Al'. Allo stesso modo, $Gore::Al e $Capone::Al sono variabili diverse,
e lo stesso vale per $main::x e $DBI::x.
E` sempre consentito includere la parte del package del nome della
variabile, e se lo fate il Perl saprà con esattezza quale
variabile intendete. Per brevità, però, tipicamente si preferisce
tralasciare il qualificatore di package. Cosa succede se lo si fa?
|
↑ Il package corrente |
Se dite semplicemente $x, Perl assume che intendiate la variabile
$x nel package corrente. Qual è il package corrente? Normalmente è
main, ma potete cambiarlo scrivendo:
package MioPackage;
nel vostro programma; da quel punto in poi, il package corrente è
MioPackage. L'unica cosa che il package corrente fa è influenzare
l'interpretazione delle variabili package che avete scritto senza il
nome del package. Se il package corrente è MioPackage, allora $x
in realtà significa $MioPackage::x. Se il package corrente è
main, allora $x indica $main::x.
Se steste scrivendo un modulo, diciamo MioModulo, probabilmente
mettereste una riga del genere all'inizio del file del modulo:
package MioModulo;
Da quel momento in poi, tutte le variabili package usate nel
file del modulo sarebbero nel package MioModulo, e potrete essere
ben certi che quelle variabili non entreranno in conflitto con le
variabili presenti nel resto del programma. Non importa se sia voi che
l'autore del modulo DBI usate una variabile chiamata $x, poiché
una di quelle $x è $MioModulo::x, e l'altra $DBI::x.
Ricordate che le variabili package sono sempre globali. Anche se non
siete nel package DBI, anche se non avete mai sentito del package
DBI, nulla può impedirvi di leggere o scrivere $DBI::errstr. Non
dovete fare nulla di speciale. $DBI::errstr, come tutte le variabili
package, è una variabile globale, ed è disponibile ovunque; tutto
quello che dovete fare per accedervi è specificare il suo nome completo.
Potreste anche scrivere
package DBI;
$errstr = 'Ha ha Tim!';
e questo modifichereebbe $DBI::errstr.
|
↑ Curiosità sulle variabili package |
Ci sono solamente altre tre cose da sapere a proposito delle variabili
package, e se volete potete saltarle in prima lettura:
-
Il package con il nome vuoto è main stesso. Quindi
$::x è uguale a $main::x per ogni x.
-
Alcune variabili sono sempre nel package main per forza. Ad esempio,
se dite
%ENV, Perl assume che intendiate %main::ENV, anche se il
package corrente non è main. Se volete %Fred::ENV, dovete indicarlo
esplicitamente, anche se il package corrente è Fred. Altri nomi
speciali in questo senso sono INC, tutti le variabili il cui nome è
costituito da un unico segno di punteggiatura come $_ e $$,
@ARGV e STDIN, STDOUT e STDERR.
-
I nomi di package, ma non i nomi di variabile, possono contenere
i caratteri
::. Potete avere una variabile chiamata $DBD::Oracle::x.
Questo indica
la variabile x nel package DBD::Oracle; non ha nulla a che fare con
il package DBD, che è svincolato. Isaac Newton non ha nulla a che fare
con Olivia Newton-John, e Newton::Isaac non ha nulla a che fare con
Newton::John::Olivia. Anche se entrambi cominciano con Newton,
l'apparenza è ingannevole. Newton::John::Olivia è nel package
Newton::John, non nel package Newton.
Questo è tutto quello che c'è da sapere a proposito della variabili
package.
Le variabili package sono globali, ed è cosa pericolosa, poiché non potete
mai essere sicuri che qualcun altro non stia facendo cose sporche
alle vostre spalle. Fino alla versione 4 di Perl, tutte le variabili erano
variabili package, e si trattava di una situazione paurosa. Così in Perl 5
sono state aggiunte nuove variabili non globali. |
↑ Variabili lessicali |
Le variabili dell'altro insieme sono chiamate variabili lessicali (vedremo
poi per quale motivo) o variabili private, poiché sono private. A volte
sono chiamate anche variabili my, poiché sono sempre dichiarate con my.
Chiamarle 'variabili locali' è una tentazione, poiché i loro effetti sono
confinati ad una piccola parte del programma, ma non fatelo, perché la
gente potrebbe pensare che state parlando dell'operatore local del Perl,
che vedremo in seguito. Quando volete una 'variabile locale' pensate a my,
non a local.
La dichiarazione
my $x;
crea una nuova variabile, chiamata $x, che è del tutto inaccessibile alla
maggior parte del programma -- qualunque porzione al di fuori del blocco
all'interno del quale la variabile è stata dichiarata. Il blocco è
chiamato lo scope della variabile. Se la variabile non fosse stata dichiarata
in nessun blocco, il suo scope sarebbe dal punto in cui è stata dichiarata
fino alla fine del file.
Potete dichiarare e inizializzare una variabile my scrivendo qualcosa come
my $x = 119;
Potete dichiararne e inizializzarne molte in un colpo solo:
my ($x, $y, $z, @args) = (5, 23, @_);
Vediamo un esempio in cui saranno utili alcune variabili private.
Considerate questa subroutine:
sub stampa_report {
@lista_impiegati = @_;
foreach $impiegato (@lista_impiegati) {
$salario = salario($impiegato);
stampa_report_parziale($impiegato, $salario);
}
}
Se anche salario() usa una variabile chiamata $impiegato, sarà la
stessa variabile usata in stampa_report, e la cosa potrebbe creare
problemi. I due programmatori responsabili di stampa_reporti() e salario()
dovranno coordinarsi per essere sicuri che non useranno mai la stessa
variabile. E` un problema. In effetti, in un progetto di medie
dimensioni, è un problema non tollerabile.
La soluzione: usare variabili my:
sub stampa_report {
my @lista_impiegati = @_;
foreach my $impiegato (@lista_impiegati) {
my $salario = lookup_salary($impiegato);
stampa_report_parziale($impiegato, $salario);
}
}
my @lista_impiegati crea una nuova variabile di tipo array che è del tutto
inaccessibile al di fuori della funzione stampa_report.
foreach my $impiegato crea una nuova variabile scalare che è del tutto
inaccessibile al di fuori del loop foreach, e lo stesso fa my $salario.
Non dovete preoccuparvi che altre funzioni nel programma stiano
manipolando queste variabili, perché non possono farlo; non sanno dove
trovarle, poiché i nomi hanno significati diversi al di fuori dello
scope delle dichiarazioni my. Queste 'variabili my' sono a volte chiamate
'lessicali' poiché il loro scope dipende soltanto dal testo stesso
del programma, e non dai dettagli dell'esecuzione, come ad esempio cosa viene
eseguito e in quale ordine. Potete determinare lo scope guardando il
codice sorgente e senza sapere cosa fa. Tutte le volte che vedete una
variabile, guardate la dichiarazione my più in alto, nello stesso
blocco. Se ne trovate una, potete star certi che la variabile non è
accessibile al di fuori di quel blocco. Se non trovate una dichiarazione
nel blocco più piccolo, guardate nel blocco più grande che lo contiene,
e così via, finchè non ne trovate una. Se non trovate una dichiarazione
my da qualche parte, allora vuol dire che la variabile è una variabile
package.
Le variabili my non sono variabili package. Non fanno parte di un
package, e non hanno qualificatore di package. Il package corrente non
ha effetto sul modo in cui esse vengono interpretate. Ecco un esempio:
my $x = 17;
package A;
$x = 12;
package B;
$x = 20;
# $x ora vale 20.
# $A::x and $B::x sono ancora indefiniti
La dichiarazione my $x = 17 all'inizio crea una nuova variabile lessicale
chiamata x il cui scope prosegue fino alla fine del file. Questo nuovo
significato di $x maschera il significato di default, cioè che
$x indicava la variabile package $x nel package corrente.
package A modifica il package corrente, ma dal momento che $x si
riferisce alla variabile lessicale e non alla variabile package,
$x = 12 non ha alcun
effetto su $A::x. In maniera analoga, dopo package B, $x = 20
modifica la variabile lessicale, e nessuna variabile package.
Alla fine del file, la variabile lessicale $x contiene 20, e le variabili
package $main::x, $A::x e $B::x sono ancora indefinite. Comunque,
se le volevate, avreste potuto accedervi usando il loro nome completo.
La massima che dovete ricordare è:
Le variabili package sono variabili globaliPer variabili private, dovete usare my
|
↑ local e my |
Quasi tutti sanno già che esiste una funzione local che ha qualcosa a che
fare con le variabili locali. Che cos'è, e che relazione ha con my?
La risposta è semplice, ma bizzarra:
my crea una variabile locale. local no.Prima di tutto, ecco quello che local $x fa in realtà. Salva il valore
corrente della variabile package $x in un posto sicuro, e lo rimpiazza
con un nuovo valore, o con undef se non è stato specificato un altro
valore. Inoltre fa in modo che il vecchio valore sia rimesso a posto quando
il controllo abbandona il blocco corrente. Le variabili su cui ha effetto
sono le variabili package, che assumono un valore locale. Ma le variabili
package sono sempre globali, e una variabile package locale non fa
eccezione. Per vedere la differenza, provate a fare così:
$lo = 'global';
$m = 'global';
A();
sub A {
local $lo = 'AAA';
my $m = 'AAA';
B();
}
sub B {
print "B ", ($lo eq 'AAA' ? 'puo`' : 'non puo`') ,
" vedere il valore di lo impostato da A.\n";
print "B ", ($m eq 'AAA' ? 'puo`' : 'non puo`') ,
" vedere il valore di m impostato da A.\n";
}
Questo stampa:
B puo` vedere il valore di lo impostato da A.
B non puo` vedere il valore di m impostato da A.
Che cosa è successo? La dichiarazione local in A ha messo un nuovo valore
temporaneo, AAA, nella variabile package $lo. Il vecchio valore,
global,
sarà ripristinato quando A ritorna, ma prima che questo accada, A chiama
B. B non ha problemi ad accedere al contenuto di $lo, poiché $lo è una
variabile package e le variabili package sono sempre disponibili ovunque,
e quindi vede il valore AAA impostato da A.
Al contrario, la dichiarazione my ha creato una nuova variabile con scope
lessicale chiamata $m, che è visibile solamente all'interno della funzione
A. Fuori da A, $m conserva il suo vecchio significato: si riferisce alla
variabile package $m, che ha ancora il valore global. Questa è la variabile
vista da B. Non vede il valore AAA poiché la variabile che ha quel valore
è una variabile lessicale, che esiste soltanto all'interno di A. |
↑ A cosa serve local? |
Poiché local in effetti non crea variabili locali, esso non è di grande
utilità. Se, nell'esempio precedente, B avesse modificato il valore
di $lo, allora il valore impostato da A sarebbe stato sovrascritto.
Questo è esattamente quello che non vogliamo che accada. Vogliamo che ogni
funzione abbia le sue variabili che non possono essere toccate dagli
altri. E` quello che fa my.
Perché esiste local, allora? Per ragioni storiche, al 90%.
Le prime versioni del Perl avevano soltanto variabili globali.
local era molto facile da implementare, e fu aggiunto in Perl 4 come
soluzione parziale al problema delle variabili locali. Poi, in
Perl 5, con del lavoro ulteriore vennero aggiunte al linguaggio delle vere
variabili locali. Ma il nome local era già stato preso, quindi la nuova
caratteristica viene invocata con il nome my. my è stato scelto perché
suggerisce privacy, e anche perché è molto breve; si suppone che
la brevità incoraggi ad usarlo al posto di local. my è inoltre più
veloce di local. |
↑ Quando usare my e quando usare local |
|
Usate sempre my; non usate mai local Avevo detto che era facile, no? |
↑ Altre proprietà delle variabili my |
Ogni volta che il controllo raggiunge una dichiarazione my, Perl crea
una variabile nuova. Per esempio, questo codice stampa x = 1 cinquanta
volte:
for (1 .. 50) {
my $x;
$x++;
print "x = $x\n";
}
Ottenete una nuova variabile $x, inizializzata ad undef, ogni volta che
il controllo attraversa il ciclo.
Se la dichiarazione fosse stata al di fuori del ciclo, il controllo l'avrebbe
vista una volta sola, e ci sarebbe stata una sola variabile:
{ my $x;
for (1 .. 50) {
$x++;
print "x = $x\n";
}
}
Questo stampa x = 1, x = 2, x = 3, ... x = 50.
Potete usare questa tecnica per un utile trucco. Supponete di avere una
funzione che ha bisogno di ricordare un valore da una chiamata all'altra. Per
esempio, considerate un generatore di numeri casuali. Un tipico generatore
di numeri casuali (come la funzione rand del Perl) ha al suo interno un seme.
Il seme è semplicemente un numero. Quando chiedete al generatore un numero
casuale, la funzione compie delle operazioni che rimescolano il seme, e
ritorna il risultato. Inoltre salva il risultato e lo usa come seme per
la prossima volta che la funzione sarà richiamata.
Ecco un codice tipico: (l'ho preso dallo standard ANSI C, ma non ha un
comportamento soddisfacente, quindi non usatelo per qualcosa di
importante)
$seed = 1;
sub my_rand {
$seme = int(($seme * 1103515245 + 12345) / 65536) % 32768;
return $seme;
}
E un tipico output:
16838
14666
10953
11665
7451
26316
27974
27550
C'è un problema. $seed è una variabile globale, e questo significa
che dobbiamo preoccuparci che qualcuno possa inavvertitamente
alterarla. Oppure potrebbero alterarla di proposito, il che pregiudicherebbe
il resto del programma. Che cosa succederebbe se la funzione venisse usata
in un programma di gioco d'azzardo, e qualcuno alterasse il generatore
di numeri casuali?
Non possiamo dichiarare $seed come variabile my nella funzione:
sub my_rand {
my $seed;
$seed = int(($seed * 1103515245 + 12345) / 65536) % 32768;
return $seed;
}
Se lo facessimo, verrebbe inizializzata a undef ogni volta che chiamiamo
my_rand. Dobbiamo conservare il suo valore tra una chiamata e l'altra di
my_rand.
Ecco la soluzione:
{ my $seed = 1;
sub my_rand {
$seed = int(($seed * 1103515245 + 12345) / 65536) % 32768;
return $seed;
}
}
La dichiarazione è al di fuori della funzione, così avviene una sola volta,
nel momento in cui il programma viene compilato, non tutte le volte che la
funzione viene chiamata. Ma è una variabile my, ed è in un blocco, quindi
è accessibile soltanto dal codice contenuto nel blocco. my_rand è la sola
altra cosa nel blocco, quindi la variabile $seed è accessibile soltanto
dalla funzione my_rand.
$seed, usata come in questo esempio, è talvolta chiamata variabile
statica, poiché rimane la stessa da una chiamata all'altra della funzione.
(E perché c'è una caratteristica simile nel linguaggio C che è attivata
dalla parola chiave static).
|
↑ Curiosità su my |
-
Non potete dichiarare una variabile my se il suo nome è un
carattere di punteggiatura, come
$_, @_ o $$. Non potete dichiarare
come my le variabili backreference quali $1, $2, .... Gli autori di
my hanno pensato che sarebbe stato troppo ingannevole.
-
Ovviamente, non potete dire my
$DBI::errstr, perché è
contraddittorio -- dice che la variabile package $DBI::errstr è ora
una variabile lessicale. Ma potete dire local $DBI::errstr, salva il
contenuto corrente di $DBI::errstr e fa in modo che venga ripristinato
al termine del blocco.
-
Novità nel Perl 5.004, ora potete scrivere
foreach my $i (@list) {
per confinare $i nello scope del ciclo. In maniera analoga,
for (my $i=0; $i<100; $i++) {
confina lo scope di $i al ciclo for.
|
↑ Dichiarazioni |
Se state scrivendo una funzione, e volete che abbia variabili private, dovete
dichiarare le variabili con my. Cosa succede se lo dimenticate?
sub funzione {
$x = 42; # Oops, avrebbe dovuto essere my $x = 42.
}
In questo caso, la vostra funzione modifica la variabile package $x. Se
steste usando la variabile per qualche altro scopo, potrebbe essere un
disastro per il vostro programma.
Recenti versioni del Perl dispongono di una protezione opzionale
contro questo problema, che se volete potete attivare. Se mettete
use strict 'vars';
all'inizio del vostro programma, Perl pretenderà che le variabili package
abbiano un qualificatore di package esplicito. La $x in $x = 42 non ha
tale qualificatore, quindi il programma non verrà compilato; al contrario,
il compilatore terminerà l'esecuzione con il seguente messaggio:
Global symbol "$x" requires explicit package name at ...
Se volete che $x sia una variabile my privata, dovete tornare
indietro e aggiungere my. Se invece volete davvero una variabile
package globale, allora dovete tornare indietro e cambiare con
$main::x = 42;
o quel che è appropriato.
Dicendo soltano use strict si attiva strict vars, ma anche altri
controlli.
Consultate perldoc strict per dettagli.
Ora immaginate di scrivere Algorithm::KnuthBendix, e di volere la protezione
di strict vars. Ma avete paura di non essere in grado di finire il modulo
perché le vostre dita si stancano a scrivere $Algorithm::KnuthBendix::Error
tutte le volte.
Potete salvare le vostre dita e dire a strict vars di fare un'eccezione:
package Algorithms::KnuthBendix;
use vars '$Error';
Questo impedisce alla variabile $Algorithm::KnuthBendix::Error di provocare
un errore di strict vars se la nominate con il suo nome breve, $Error.
Potete anche disattivare strict vars nello scope di un singolo blocco
scrivendo:
{ no strict 'vars';
# strict vars e` spento per il resto del blocco.
} |
↑ Riassunto |
Le variabili package sono sempre globali. Hanno un nome e un qualificatore di
package. Potete omettere il qualificatore di package, e in questo caso Perl
userà un default, che potete cambiare con la dichiarazione package. Per
le variabili private, usate my. Non usate local: è obsoleto.
Dovreste evitare di usare variabili globali perché può essere difficile
assicurarsi che non ci siano due sezioni del programma che usano l'uno
la variabile dell'altro per errore.
Per evitare di usare variabili globali per errore, aggiungete
use strict 'vars' al vostro programma. Esso controlla che ogni variabile
sia dichiarata privata, o sia esplicitamente qualificata con un qualificatore
di package, o sia esplicitamente dichiarata con use vars. |
↑ Glossario |
|
↑ Note |
-
I revisori tecnici si sono lamentati della mia massima 'Non usate mai
local'. Ma il 97% delle volte, la massima è del tutto corretta.
local ha alcuni usi, ma solo alcuni, e non saltano fuori troppo spesso,
quindi li ho lasciati perdere, poiché il proposito del tutorial è presentare
il 97% dell'utilità nel 50% dello spazio.
Mi era rimasta la paura di ricevere mail noiose da persone che avrebbero
detto: "Hai dimenticato di dire che local può essere usato per fare
questo e quello...". Così nel frontespizio dell'articolo,
ho promesso di rilasciare "Seven Useful Uses for local" nel giro di tre
mesi. L'ho detto più che altro per evitare di essere disturbato a
proposito di local. Ma alla fine l'ho scritto, ed è stato pubblicato
qualche tempo dopo.
"The Seven Useful Uses of local" è disponibile sul sito
(http://perl.plover.com/local.html). È comparso su The Perl Journal,
numero 14.
-
Ecco un altro argomento potenzialmente interessante, che ho lasciato
da parte per esigenze di spazio e per maggior chiarezza. Ho ricevuto una
mail da Robert Watkins con un programma che stava scrivendo che non
funzionava. Il bug essenzialmente era una cosa del genere:
my $x;
for $x (1..5) {
s();
}
sub s { print "$x, " }
Robert voleva che stampasse 1, 2, 3, 4, 5, ma non lo faceva. Invece,
stampava , , , , , . Dove andavano i valori di $x?
Il fatto è che normalmente, quando scrivete qualcosa come:
for $x ( ... ) { }
Perl vuole confinare il valore della variabile indice all'interno del
loop. Se $x è una variabile package, farà finta che abbiate scritto
questo:
{ local $x; for $x ( ... ) { } }
Ma se $x è una variabile lessicale, farà finta che abbiate scritto
questo, invece:
{ my $x; for $x ( ... ) { } }
Questo significa che la variabile indice non sarà propagata alle
subroutines, anche se sono nello scope della dichiarazione originale.
Probabilmente non avrei dovuto dilungarmi fino a questo punto, poiché
perlsyn lo descrive bene:
... la variabile è implicitamente locale al ciclo e il suo valore
è ripristinato all'uscita. Se la variabile è stata precedentemente
dichiarata con my, viene usata questa variabile al posto di quella
globale, ma è comunque localizzata al ciclo. (Notate che che una
variabile lessicale può causare problemi se avete subroutine
o dichiarazioni format all'interno del ciclo che fanno riferimento
ad essa.) Secondo me, limitare la visilità in senso lessicale ("to scope lexically")
è stato probabilmente un errore. Se aveste voluto questo, avreste scritto
direttamente for my $x .... Quello che vorrei avesse fatto è localizzare
la variabile lessicale: potrebbe salvare il valore della variabile lessicale
prima del ciclo, per poi ripristinarlo successivamente. Ma ci possono essere
ragioni tecniche per cui questo non può essere fatto, visto che nemmeno
questo funziona:
my $m;
{ local $m = 12;
...
}
La local fallisce con questo messaggio d'errore:
Can't localize lexical variable $m...
Ci sono state discussioni su P5P sulla possibilità di farlo funzionare,
ma sospetto che non sia banale.
-
Aggiunto il 5/1/2001: Perl 5.6.0 introduce la nuova dichiarazione
our( ... ). La sua sintassi è la stessa di my(), e si tratta di un
sostituto di use vars.
Senza entrare nei dettagli, our() è come use vars; il suo unico effetto
è quello di dichiarare variabili in maniera tale che esse siano
escluse dai controlli di use strict 'vars'. Ha due vantaggi rispetto
a use vars;, però: la sintassi è meno strana, e il suo effetto è
lessicale. In altre parole, l'eccezione a strict causata da our()
è valida soltanto fino alla fine del blocco corrente:
use strict 'vars';
{
our($x);
$x = 1; # L'uso della variabile globale $x qui e` OK
}
$x = 2; # L'uso di $x, qui, e` come al solito un errore
# segnalato a tempo di compilazione
Quindi laddove use vars '$x' dichiara che va bene usare la variabile
globale $x dappertutto, our( $x ) permette di dire che la variabile
globale $x è consentita solo in certe parti del programma, ma che
deve essere riportato un errore se accidentalmente la usate
altrove.
-
Aggiunto il 5/1/2000: Ecco un piccolo dettaglio che sorprende la gente.
Considerate questo piccolo programma:
use strict 'vars';
my @linee = <>;
my @ordinate = sort inverso @linee;
print @ordinate;
sub inverso { $b cmp $a }
Non abbiamo dichiarato $a e $b, quindi sono variabili globali. In
effetti,
devono essere globali, poiché l'operatore sort deve essere in grado di
inizializzarle per la funzione inverso. Perché strict non produce un
errore?
Le variabili $a e $b sono escluse dai controlli di strict vars,
esattamente per questa ragione.
↑ |
|