perl scope perl6

¿Es un defecto de diseño que los subs de Perl no tengan un alcance léxico?



scope perl6 (7)

{ sub a { print 1; } } a;

Un error, ¿verdad?

a no debería estar disponible desde afuera.

¿Funciona en Perl 6 *?

* Perdón por no haberlo instalado aún.


Las subrutinas con nombre en Perl se crean como nombres globales. Otras respuestas han mostrado cómo crear una subrutina léxica asignando un sub anónimo a una variable léxica. Otra opción es usar una variable local para crear un sub de ámbito dinámico.

Las principales diferencias entre los dos son el estilo de llamada y la visibilidad. El sub de ámbito dinámico se puede llamar como un sub nombrado, y también será visible globalmente hasta que se deje el bloque en el que está definido.

use strict; use warnings; sub test_sub { print "in test_sub/n"; temp_sub(); } { local *temp_sub = sub { print "in temp_sub/n"; }; temp_sub(); test_sub(); } test_sub();

Esto debería imprimir

in temp_sub in test_sub in temp_sub in test_sub Undefined subroutine &main::temp_sub called at ...


Las subrutinas tienen un ámbito de paquete, no de ámbito de bloque.

#!/usr/bin/perl use strict; use warnings; package A; sub a { print 1, "/n"; } a(); 1; package B; sub a { print 2, "/n"; } a(); 1;


Si ve el código compilar, ejecutar e imprimir "1", entonces no está experimentando un error.

Parece que espera que las subrutinas solo se puedan llamar dentro del alcance léxico en el que están definidas. Eso sería malo, porque eso significaría que uno no podría llamar a las subrutinas definidas en otros archivos. ¿Tal vez no se dio cuenta de que cada archivo se evalúa en su propio alcance léxico? Eso permite a los gustos de

my $x = ...; sub f { $x }


En Perl 6, los subs tienen un alcance léxico, por lo que el código arroja un error (como varias personas ya han señalado).

Esto tiene varias implicaciones interesantes:

  • Los subidos nombrados anidados funcionan como cierres adecuados (ver también: la advertencia "no se quedará compartida" en perl 5)
  • la importación de subs desde los módulos funciona en ámbitos léxicos
  • las funciones incorporadas se proporcionan en un alcance léxico externo (el "ajuste") alrededor del programa, por lo que anular es tan fácil como declarar o importar una función del mismo nombre
  • como los lexpads son inmutables en tiempo de ejecución, el compilador puede detectar llamadas a rutinas desconocidas en el momento de la compilación (niecza ya lo hace, Rakudo solo en la rama "optimizador").

Sí, creo que es un defecto de diseño, más específicamente, la elección inicial de utilizar el alcance dinámico en lugar del alcance léxico realizado en Perl, lo que naturalmente conduce a este comportamiento. Pero no todos los diseñadores y usuarios de idiomas estarían de acuerdo. Entonces, la pregunta que hace no tiene una respuesta clara.

El ámbito léxico se agregó en Perl 5, pero como característica opcional, siempre debe indicarlo específicamente. Con esa opción de diseño estoy totalmente de acuerdo: la compatibilidad con versiones anteriores es importante.


A riesgo de otra reprimenda por @tchrist, estoy agregando otra respuesta para completar. Se espera que Perl 5.18, aún no publicado, incluya subrutinas léxicas como una característica experimental.

Aquí hay un enlace a la documentación relevante. De nuevo, esto es muy experimental, no debe usarse para el código de producción por dos razones:

  1. Puede que aún no esté bien implementado
  2. Puede ser eliminado sin previo aviso

¡Así que juega con este nuevo juguete si quieres, pero has sido advertido!


¿Estás preguntando por qué el submarino es visible fuera del bloque? Si es así, es porque la palabra clave sub tiempo de compilación coloca el sub en el espacio de nombres main (a menos que utilice la palabra clave del package para crear un nuevo espacio de nombres). Puedes intentar algo como

{ my $a = sub { print 1; }; $a->(); # works } $a->(); # fails

En este caso, la palabra clave sub no está creando un sub y poniéndolo en el espacio de nombres main , sino que crea una subrutina anónima y la almacena en la variable de ámbito léxico. Cuando la variable sale del alcance, ya no está disponible (generalmente).

Para leer más echa un vistazo a perldoc perlsub

Además, ¿sabía que puede inspeccionar la forma en que el analizador de Perl ve su código? Ejecute perl con el flag -MO=Deparse como en perl -MO=Deparse yourscript.pl . Su código original analiza como:

sub a { print 1; } {;}; a ;

El sub se compila primero, luego se ejecuta un bloque sin código, luego se llama a.

Para mi ejemplo en Perl 6, vea: Success , Failure . Tenga en cuenta que en Perl 6, la desreferencia es . no -> .

Editar: He agregado otra respuesta sobre el nuevo soporte experimental para las subrutinas léxicas esperadas para Perl 5.18.