Question très intéressante. J'écris ceci comme une réponse à la place d'un commentaire parce que ce sera plutôt long, mais il y a encore quelques morceaux dont je ne suis pas entièrement sûr.
Je crois que votre intuition est correcte et que c'est une forme d'autovivification.
Devel::Peek peut répandre plus de lumière sur ce qui se passe.
j'ai changé votre code un peu:
use warnings;
use strict;
use Devel::Peek;
$|++;
BEGIN {
Dump(\&mysub);
print \&mysub;
};
sub mysub {};
Dump(\&mysub);
print \&mysub;
I ajouté $|++
de sorte que tampon ne sera pas cause de confusions, et a ajouté des appels à Devel::Peek::Dump
pour examiner la référence \&mysub
. Ici, la sortie sur mon système:
SV = IV(0x2628628) at 0x2628638
REFCNT = 1
FLAGS = (TEMP,ROK)
RV = 0x26286e0
SV = PVCV(0x2640750) at 0x26286e0
REFCNT = 2
FLAGS = (DYNFILE)
COMP_STASH = 0x25ffdb0 "main"
ROOT = 0x0
GVGV::GV = 0x26287a0 "main" :: "mysub"
FILE = "/tmp/autov.pl"
DEPTH = 0
FLAGS = 0x1000
OUTSIDE_SEQ = 0
PADLIST = 0x0
OUTSIDE = 0x0 (null)
CODE(0x26286e0)SV = IV(0x25fff20) at 0x25fff30
REFCNT = 1
FLAGS = (TEMP,ROK)
RV = 0x26286e0
SV = PVCV(0x2640750) at 0x26286e0
REFCNT = 2
FLAGS = (DYNFILE)
COMP_STASH = 0x25ffdb0 "main"
START = 0x262ea50 ===> 1
ROOT = 0x262ea10
GVGV::GV = 0x26287a0 "main" :: "mysub"
FILE = "/tmp/autov.pl"
DEPTH = 0
FLAGS = 0x1000
OUTSIDE_SEQ = 371
PADLIST = 0x2648620
PADNAME = 0x2630180(0x2667f70) PAD = 0x2628770(0x262f020)
OUTSIDE = 0x2600140 (MAIN)
CODE(0x26286e0)
Notez comment les changements de sortie de l » Dump
entre les deux appels. La première fois que Dump
est appelée, nous avons juste une référence à un scalaire vide. Le deuxième deuxième, après la définition réelle de la sous-routine, vous pouvez voir les détails qui se rapportent aux sous-programmes ont été étoffés: à savoir PADLIST
(maintenant non nul), PADNAME
et START
(Je ne suis pas un expert de Perl guts mais je pense que ce est le "pointeur" réel à la sous-routine).
J'espère que cela aide. Je serais intéressé de savoir ce que vous découvrirez si vous approfondissez le problème.
Vous pouvez supprimer les deux dernières lignes, et il fonctionne. Vous pouvez également supprimer 'BEGIN {}' et il imprime toujours l'adresse et aucun avertissement ou erreur. Cependant, si vous essayez d'appeler le sub après (sans le définir), vous obtenez le sous-programme Undefined subroutine & main :: mysub', donc il n'est pas autovivifié. On dirait un bug. –
Qu'est-ce que cela fait est de créer un «stub» de sous-routine. Essentiellement, cela suffit pour permettre au code de continuer. Comme mentionné, vous ne pouvez pas appeler le sous-marin. Ce qui va casser ce code, c'est si vous essayez d'utiliser des prototypes. Il ne serait pas capable de comprendre la liste des arguments, de sorte que le code serait effectivement rompu. – stevieb