← All posts tagged Perl

Kim

В перле можно вызывать функции следующим способом:
> $ perl -e 'sub xx {print "Hello\n"}; ("xx")->(1)'
> Hello

Соответственно если внутри скобок есть какой-то вызов, то он отработает и вызов нового метода будет от результата:
> $ perl -e 'sub ss { return "xx" }; sub xx {print "Hello\n"}; (ss)->(123);'
> Hello

Тут всё прекрасно, но есть забавное поведение в случае возврата булевого значение из встроенной функции. Если возвращается false, то всё нормально:
> $ perl -e '(exists $h{1})->()'
> Undefined subroutine &main:: called at -e line 1.

А если возвращается true, то мы получаем особую перловую магию:
> $ perl -e '++$h{1}; (exists $h{1})->()'
> $

Причём возврат булевого значения из определённых пользователем методов так не работает:
> $ perl -e 'sub x {1==1}; (x)->()'
> Undefined subroutine &main::1 called at -e line 1.
> $ perl -e 'sub x {return 1==1}; (x)->()'
> Undefined subroutine &main::1 called at -e line 1.

Зато булево значение можно передавать внутрь:
> $ perl -e 'sub x {$_[0]->(1)}; x(1==1);'
> $ perl -e 'sub x {shift->(1)}; x(1==1);'
> $ perl -e 'sub x {my $x=shift; $x->(1)}; x(1==1);'
> Undefined subroutine &main::1 called at -e line 1.
> $

В чём тут магия спросите вы? А магия тут в том как перл хранит переменные и вызывает методы. Если вдруг так случилось, что в вашей скалярной (SV в терминах перловых исходников) переменной оказалась не строка "", не число 1, а волшебная переменная из кода на C под именем PL_sv_yes, которая в исходниках перла описана в pod/perlapi.pod, то при вызове метода (а это действие реализовано в методе PP(pp_entersub) в файле pp_hot.c) вы попадёте на код pp_hot.c:2856:
> if (sv == &PL_sv_yes) {		/* unfound import, ignore */
> …
>   RETURN;
> }

Таким образом знайте, что вызов метода, где в качестве ссылки на метод используется значение true, интерпретируется как импорт несуществующего модуля и игнорируется. Сраные костыли, да.