Tengo una serie de funciones de utilidad de orden superior que toman una referencia de código y aplican ese código a algunos datos. Algunas de estas funciones requieren la localización de variables durante la ejecución de las subrutinas. Al principio, yo estaba usando caller
para determinar cuál es el paquete de localizar en, de una manera similar como se muestra en este ejemplo reduce
función:En Perl, ¿cuál es la forma más confiable de determinar el paquete coderef?
sub reduce (&@) {
my $code = shift;
my $caller = caller;
my ($ca, $cb) = do {
no strict 'refs';
map \*{$caller.'::'.$_} => qw(a b)
};
local (*a, *b) = local (*$ca, *$cb);
$a = shift;
while (@_) {
$b = shift;
$a = $code->()
}
$a
}
Inicialmente esta técnica funcionó bien, sin embargo, tan pronto como he tratado de escribir un envoltorio funcionar alrededor de la función de orden superior, descubrir quién llama se vuelve complicado.
sub reduce_ref (&$) {&reduce($_[0], @{$_[1]})}
Ahora con el fin de reduce
para trabajar, necesitaría algo así como:
my ($ca, $cb) = do {
my $caller = 0;
$caller++ while caller($caller) =~ /^This::Package/;
no strict 'refs';
map \*{caller($caller).'::'.$_} => qw(a b)
};
En este punto se convirtió en una cuestión de qué paquetes para saltar, combinado con la disciplina de la que nunca se utiliza la función desde dentro de esos paquetes. Tenía que haber una mejor manera.
Resulta que la subrutina que las funciones de orden superior toman como argumento contiene suficientes metadatos para resolver el problema. Mi solución actual es usar el módulo de introspección B
para determinar el alijo de compilación de la subrutina aprobada. De esta forma, pase lo que pase entre la compilación del código y su ejecución, la función de orden superior siempre conoce el paquete correcto para localizar.
my ($ca, $cb) = do {
require B;
my $caller = B::svref_2object($code)->STASH->NAME;
no strict 'refs';
map \*{$caller.'::'.$_} => qw(a b)
};
Así que mi última pregunta es si esta es la mejor manera de determinar el paquete de la persona que llama en esta situación? ¿Hay alguna otra forma en que no haya pensado? ¿Hay algún error esperando que ocurra con mi solución actual?
Esto parece depender enormemente de la implementación ... ¿Qué tan seguro está de que nada de esto cambiará en futuras versiones de Perl?¿No sería más simple y más robusto usar objetos en lugar de funciones sin procesar, tener cada objeto almacenando una función y también recordar el paquete apropiado? – Nemo