2012-07-11 10 views
8

Empecé notando algo extraño sobre Scope::Guard.DESTROY llamado en la secuencia inesperada

  • Si UNDEF una variable $guard como la última declaración en un sub, sub del guardia se llamada más tarde de lo esperado.
  • Si no lo defino, o si hago algo (cualquier cosa) después de undef $guard, se llama cuando la referencia sale del alcance según lo documentado. Me pregunto porque.

el código es que también se encuentran here

my $sClass = 'SGuard'; 
# Uncomment to use Scope::Guard instead: 
# use Scope::Guard; $sClass = 'Scope::Guard'; 

package SGuard; 
sub new { 
    my ($class, $sub) = @_; 
    return bless { sub => $sub }, $class; 
} 

sub DESTROY { 
    my ($self) = @_; 
    $self->{sub}->(); 
} 

package main; 
sub mySub { 
    my $mySubGuard = $sClass->new(sub { 
     print "shouldDestroyFirst\n" 
    }); 

    # Do something - any no-op will do. 
    undef; 

    # Comment out this line and it works 
    undef $mySubGuard; 

    # Or uncomment the next undef line and it works. Any statement(s) or 
    # no-ops will do but we test the return value of mySub to make sure it 
    # doesn't return a reference, so undef... 

    # undef; 
} 
{ 
    my $scopeGuard = $sClass->new(sub { 
     print "shouldDestroyLast\n" 
    }); 

    # Check that mySub returns undef to ensure the reference *did* go out 
    # of scope 
    printf "mySub returned a %sdefined value\n", defined mySub() ? "" : "un"; 
} 
print "done\n"; 

En el código que he hecho mi propio hombre pobre Scope::Guard (SGuard arriba) sólo para hacer el ejemplo más simple posible. También puede usar Scope::Guard y obtener exactamente los mismos resultados que son inesperados al menos para mí.

Estoy esperando que el $mySubGuard dentro mySub() deben ser destruidos primera y la $scopeGuard en el ámbito que llama mySub() deben ser destruidos pasado. Y así obtener una salida como:

shouldDestroyFirst 
mySub returned a undefined value 
shouldDestroyLast 
done 

me sale por encima de la salida si uso undef $mySubGuard línea en mySub. Si yo no uso undef $mySubGuard línea en mySub, consigo debajo de la salida:

mySub returned a undefined value 
shouldDestroyLast 
shouldDestroyFirst 
done 

Por lo tanto, parece que el $mySubGuard de mySub() se destruye después de las variables locales con el ámbito exterior son destruidos.

¿Por qué el comportamiento difiere solo porque undef una variable que está a punto de ir fuera de alcance de todos modos? ¿Y por qué importa si se hace algo después de ?

Respuesta

1

Parece que es una especie de optimización. Si undef es una variable y no la usa después, se pone en algún tipo de cola para verificar magia o algo así. Pero si haces algo después, lo hará DESTRUIR en ese momento.

Además, podría haber un error que ya está undef -ing en digamos un "contexto de retorno", hay una copia de la variable que está siendo inspeccionado por algo. Y quizás Perl conserve una referencia que luego limpia y al final del alcance de la llamada.

también se dará cuenta de que cualquier otra declaración después undef -ing los resultados de guardia en el comportamiento esperado. Incluyendo la recomendada por PBP que termina con todos los subs con return. Una de las razones explícitas de Damian fue que evita los efectos secundarios inesperados.

Problema resuelto: tan fácil como undef -un guardián, puede ejecutar su controlador directamente. No defina guardias como la última declaración (implícita) de un submarino. Tiene una razón para proteger los guardias de manera explícita, como por ejemplo, si desea ejecutar su controlador en ese momento, para realizar el procesamiento posterior de.

Es confuso e inesperado, pero definitivamente no es algo que deba surgir en el código terminado o estandarizado.

Cuestiones relacionadas