Почему этот Perl создает «Не ссылка на КОД? «

Мне нужно удалить метод из таблицы символов Perl во время выполнения. Я попытался сделать это с помощью undef & Square :: area , который удаляет функцию, но оставляет некоторые следы. В частности, когда вызывается $ square-> area () , Perl жалуется, что это «Не ссылка на КОД», а не «Неопределенная подпрограмма и Square :: area вызвана», что я ожидал.

Вы можете спросить: «Почему это важно? Вы удалили функцию, зачем вы ее вызываете?» Ответ в том, что я не называю это Perl. Square наследуется от Rectangle, и я хочу, чтобы цепочка наследования передавала $ square-> area через & Rectangle :: area , но вместо того, чтобы пропускать Square, где метод не существует, и затем проваливается в прямоугольник ' s area (), вызов метода завершается с сообщением «Not a CODE reference».

Как ни странно, это происходит только тогда, когда & Square :: area было определено назначением typeglob (например, * area = sub {... } ). Если функция определена с использованием стандартного подхода подобласти {} , код работает, как ожидалось.

Также интересно, что удаление всего глобуса работает должным образом. Просто не отменяйте определение самой подпрограммы.

Вот небольшой пример, который иллюстрирует симптом и контрастирует с правильным поведением:

#!/usr/bin/env perl
use strict;
use warnings;

# This generates "Not a CODE reference". Why?
sub howdy; *howdy = sub { "Howdy!\n" };
undef &howdy;
eval { howdy };
print $@;

# Undefined subroutine &main::hi called (as expected)
sub hi { "Hi!\n" }
undef &hi;
eval { hi };
print $@;

# Undefined subroutine &main::hello called (as expected)
sub hello; *hello = sub { "Hello!\n" };
undef *hello;
eval { hello };
print $@;

Обновление : с тех пор я решил эту проблему с помощью Package :: Stash (спасибо @Ether), но я все еще не понимаю, почему это вообще происходит. perldoc perlmod говорит:

основной пакет;

sub Some_package :: foo {...} # & foo, определенный в Some_package

Это просто сокращение для присвоения typeglob во время компиляции:

BEGIN {* Some_package :: foo = sub {...}}

Но похоже, что это не просто сокращение , потому что они вызывают разное поведение после отмены определения функции. Я был бы признателен, если бы кто-нибудь сказал мне, является ли это (1) неправильной документацией, (2) ошибкой в ​​perl или (3) PEBCAK.

5
задан KingPong 13 January 2011 в 00:42
поделиться