mercoledì 12 febbraio 2014

tail-call goto

In Perl l'istruzione goto ha diversi significati e utilizzi: oltre al "classico" salto verso una label infatti permette anche il salto verso una funzione da un'altra funzione. In questo caso avviene quella che viene spesso definita una tail-call, poiche' il salto rappresenta l'ultima istruzione eseguita sullo stack frame corrente.
In occasione del salto tail-call gli argomenti local vengono resettati e la funzione di destinazione viene invocata come fosse stata invocata individualmente rimuovendo lo stack attuale; i parametri @_ mantengono il loro valore attuale (ossia le modifiche sono propagate).
Si consideri il seguente esempio:

#!/usr/bin/env perl -w

use v5.10;

$value = 10;

sub foo{
say "Inside foo and the value is $value";
say join ", ", caller;
}

sub bar{
local $value = 20;
say "Inside bar and the value is $value";
goto &foo;
}


say "Let's start...";
say join ", ", caller;
say "...and now the magic!";
bar;


L'invocazione di caller serve a rendere visibile lo stack di chiamata, che nel caso del main e' assente.
L'invocazione di bar effettua una modifica a $value, e poi una tail-call verso foo. A questo punto Perl rimuove dallo stack i dati di bar (rimuovendo quindi la localizzazione di $value) e invoca foo come se fosse stata chiamata direttamente dal main. E infatti il programma produce il seguente output:

Let's start...

...and now the magic!
Inside bar and the value is 20
Inside foo and the value is 10
main, test.pl, 22

Da notare che l'output di caller produce un solo frame invocante, il main, anche se a prima vista foo() e' stata invocata tramite bar().
Da notare che il sigillo di subroutine e' obbligatorio per permettere a goto di comprendere che si tratta di un salto ad una funzione, non ad una label.

Nessun commento: