|
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
globali
Per 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.
↑ |
|