Questo warning viene generato durante la compilazione se, per errore, tentate di dichiarare due volte la stessa variabile nello stesso scope.

"my" variable ... masks earlier declaration in same scope at ... line ...

Che senso ha e perché invece ri-dichiarare delle variabili in ogni iterazione di un ciclo funziona?

Se non posso scrivere my $x due volte nello stesso scope, come faccio a resettare la variabile?

Vediamo la differenza tra i seguenti casi:

Semplice script

use strict;
use warnings;

my $x = 'this';
my $z = rand();
my $x = 'that';
print "OK\n";

In questo caso ricevo il seguente warning durante la compilazione:

"my" variable $x masks earlier declaration in same scope at ... line 7. )

Trattandosi di un warning, l'esecuzione dello script stampa comunque anche "OK".

Blocco in un'istruzione condizionale

use strict;
use warnings;

my $z = 1;
if (1) {
    my $x = 'this';
    my $z = rand();
    my $x = 'that';
}

Questo genera il seguente warning:

"my" variable $x masks earlier declaration in same scope at ... line 7.

In entrambi i casi abbiamo dichiarato $x due volte nello stesso scope, per cui è stato generato un warning durante la compilazione.

Nel secondo esempio dichiariamo anche $z due volte, ma non viene generato alcun warning. Ciò è dovuto al fatto che la $z nel blocco è in uno scope diverso.

Scope di una funzione

Un po' di codice dentro una funzione:

use strict;
use warnings;

sub f {
    my $x = 'this';
    my $z = rand();
    my $x = 'that';
}
f(1);
f(2);

Anche in questo caso durante la compilazione ricevete una sola volta il warning per la variabile $x. Anche se la variabile $z viene creata ripetutamente, una volta per ogni chiamata alla funzione, questo non crea problemi. La variabile $z non genera warning: Perl può creare due volte la stessa variabile, siete voi che non potete farlo. Almeno non nello stesso scope.

Scope di un ciclo for

Stesso codice, ma in un ciclo:

use strict;
use warnings;

for (1 .. 10) {
    my $x = 'this';
    my $z = rand();
    my $x = 'that';
}

Anche questo genera un warning per $x una sola volta(!) e non genera alcun warning per $z.

In questo codice la stessa cosa viene ripetuta ad ogni iterazione: Perl alloca la memoria per la variabile $z ad ogni iterazione.

Che cosa significa "my"?

Il significato di my $x è quello di dire a perl, e in particolare a strict, che volete usare una variabile privata $x nello scope corrente. In mancanza di ciò, perl cerca una dichiarazione negli scope superiori e se non riesce a trovarla genera un errore di compilazione Global symbol requires explicit package name Ogni ingresso in un blocco, ogni chiamata a una funzione, ogni iterazione in un loop è un nuovo mondo.

D'altra parte, se scrivete my $x due volte nello stesso scope significa che state cercando di dire a Perl la stessa cosa due volte. Non è necessario e in genere indica che c'è un errore da qualche parte.

In altre parole, il warning che riceviamo è dovuto alla compilazione del codice e non alla sua esecuzione. È legato alla dichiarazione della variabile da parte dello sviluppatore e non alle allocazioni di memoria fatte da perl durante l'esecuzione.

Come si resetta una variable?

Se non possiamo scrivere my $x; due volte nello stesso scope, come facciamo a resettarne il valore?

Anzitutto, se una variabile è dichiarata in uno scope, ovvero tra parentesi graffe, verrà automaticamente distrutta non appena l'esecuzione esce dallo scope.

Se volete resettare una variabile scalare nello scope corrente, assegnatele il valore undef mentre se è un array o un hash, assegnatele una lista vuota:

$x = undef;
@a = ();
%h = ();

Per riassumere: "my" dice a perl che volete usare una variabile. Quando Perl esegue il codice dove c'è la variabile "my" alloca la memoria per la variabile e il suo contenuto. Quando Perl esegue $x = undef; oppure @x = (); oppure undef @x; rimuove il contenuto della variabile.