[Perl] Fragmento de un closure ...

Salvador Ortiz Garcia sog@msg.com.mx
Wed, 15 Oct 2003 11:04:59 -0500


On Mon, 2003-10-13 at 22:57, Manuel Rabade wrote:
> On Mon, Oct 13, 2003 at 09:35:09PM -0500, Sergio Rojas wrote:
> > Saludos Perleros!
> > 
> > Tengo el siguiente fragmento de un closure:

Nada de fragmento, plantilla es un generador de closures en toda la
forma.

> > 
> > 1 sub plantilla{
> > 2    my $x = $_[0];
> > 3    return sub {
> > 4	print "$x $_[0] \n";
> > 5    }   	
> > 6 }	
> > 
> > 
> > La pregunta es: porque el escalar $x conserva su valor en las lineas
> > 2 y 4, y el elemento del arreglo $_[0] no. Se sobreescribe o algo asi
> > al llamar la subrutina anidada?
> > 
> 
> Poruque el arreglo @_ contiene los parametros pasados a una subrutina y al
> invocar 'sub' se limpia @_ y se le cargan los valores que le pasas, en este caso
> ninguno.

Salvo que en el código mostrado nadie aún está invocando al closure,
solo creándolo. (La invocación a 'sub', constructor del closue no le
hace nada a @_)

> 
> Ademas por el ambito de $x conservara su valor en todo el bloque en el que fue
> declarada (de la linea 1 a 6).
> 
> Corrijanme si me equivoco gurus de la lista :-P.

Fundamentalmente tu explicación es correcta. Sólo la formalizaré:

Al llamar a plantilla, con

  my $closureA = platilla('foo');

Es claro que en [2] se crea una variable lexicográfica '$x' con el valor
'foo', tomado de los argumentos de la invocación de plantilla.

En [3] plantilla crea un closure, que precisamente por serlo captura el
ambito lexicográfico, y plantilla devuelve una referencia al mismo.

Por lo tanto '$closureA' es una referencia al closure creado, que si
ahora invocamos con:

  &{$closureA}('valor');  # o $closureA->('valor'); al gusto del cliente

'valor' se convierte en argumento del closure, en $_[0], y $x conserva
el valor que el closure tiene capturado en su ambito.

De ahí la salida "foo valor".

Si a continuación se ejecutara:

  my $clousureB = plantilla('bar');

Se estaría creando un segundo closure, que en el ambito capturado
tendría a 'bar' como valor de '$x', pero el valor de '$_[0]' dependerá
de lo que se le pase como argumento al momento al momento de que se le
invocara:

  $closureB->('otro');

Resultando en "bar otro".

De lo anterior queda claro que mientras '$x' en las líneas [2] y [3] es
la misma variable, '$_[0]' en [2] es el argumento con que se invoca a
plantilla, y '$_[0]' en [3] es el argumento con que se invoque al
closure creado.

Y tanto $closureA como $closureB tienen capturada su propia instancia de
'$x'.

Saludos.

-- 
Salvador Ortiz Garcia <sog@msg.com.mx>
Matías Software Group