Lo scopo dello scope

Table of Contents

This is my translation of Coping with Scoping by Mark Jason Dominus. Originally published on www.perl.it (July 2003). I reproduced it here with some corrections (July 2017).

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. Il che 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 il contenuto 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 Lisp, all'estremamente barocco, in linguaggi quali C++. Perl sfortunatamente cade in qualche punto all'estremità rococò di questa scala.

Il problema di 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: Perl ha due insiemi di variabili completamente separati e indipendenti. Uno è un'eredità di Perl 4, 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 cose importanti da sapere a proposito delle variabili package:

  1. La variabili package sono quello che ottenete se non specificate diversamente.
  2. Le variabili package sono sempre globali.

Globali significa che le variabili package sono sempre visibili ovunque in ogni 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, che sono analoghe al nome e al cognome della variabile. Potete chiamare il Vicepresidente degli Stati Uniti 'Al', se volete, ma si tratta di una considerevole abbreviazione del suo nome completo, che è 'Al Gore'. 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.

È sempre consentito includere la parte del package del nome della variabile, e se lo fate 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 modificherebbe $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:

  1. Il package con il nome vuoto è main stesso. Quindi $::x è uguale a $main::x per ogni x.
  2. 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, tutte le variabile il cui nome è costituito da un unico segno di punteggiatura come $_ e $$, @ARGV e STDIN, STDOUT e STDERR.
  3. 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, che è cosa pericolosa perché non potete mai essere sicuri che qualcun altro non stia facendo cose losche alle vostre spalle. Fino alla versione 4 di Perl tutte le variabili erano variabili package, e si trattava di una situazione preoccupante. 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, però non fatelo, perché la gente potrebbe pensare che state parlando dell'operatore local di 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 risulta del tutto inaccessibile alla maggior parte del programma – a qualunque porzione, cioè, 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 è l'uso di 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 myrand. Dobbiamo conservare il suo valore tra una chiamata e l'altra di myrand.

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. myrand è la sola altra cosa nel blocco, quindi la variabile $seed è accessibile soltanto dalla funzione myrand.

$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

  1. 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.
  2. 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.
  3. 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

Variabile globale Globale Variabile lessicale Dichiarazione local my Dichiarazione my Variabile my Dichiarazione package Qualificatore di package Variabile package Variabile privata Scope use strict vars use vars

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.

Author: Stefano Rodighiero

Created: 2019-12-31 Tue 12:19

Validate