Подтвердить что ты не робот

Это ошибка с прототипом Perl glob?

Без особых причин я играл с прототипом glob (*) и видел, что он будет делать, когда аргумент является определенной подпрограммой.

С учетом следующего кода:

sub test (*) {print "[@_]\n"}
sub blah ($) {"blah got @_"}

Если вы пишете test blah;, вы получите синтаксическую ошибку Not enough arguments for main::blah...

Если вы пишете test blah 1;, программа компилирует и печатает [blah]

Если вы пишете test blah die;, программа компилирует, печатает [blah] и не умирает.

Если вы пишете test blah(1);, программа компилирует и печатает [blah got 1]

Если вы пишете test blah(die);, программа компилируется и затем умирает.

Два последних примера явно являются приложением "если он выглядит как вызов подпрограммы, это правило вызова подпрограммы".

Однако примеры без округлых скобок мне кажутся ошибкой. Поскольку, по-видимому, происходит то, что, несмотря на то, что он находится в глобальном контексте, парсер по-прежнему рассматривает blah как прототипированную функцию, которая требует аргумента. Но когда компиляция произносится и выполняется, аргумент blah полностью отбрасывается, а строка 'blah' вместо этого передается в test.

Ниже приведен пример конструкции test blah die;, проходящей через B::Deparse:

$ perl -MO=Deparse,-p -e 'sub test (*) {print "[@_]\n"} sub blah ($) {"blah got @_"} test blah die;'
sub test (*) {
    print("[@_]\n");
}
sub blah ($) {
    "blah got @_";
}
&test('blah');
-e syntax OK

Итак, как вы можете видеть, die полностью удаляется из op-дерева.

Итак, мой вопрос: если другие считают это поведение ошибкой? Является ли поведение документированным где угодно? Если это ошибка, стоит ли ее исправлять?

4b9b3361

Ответ 1

Прототипы в Perl плохие новости. Они ужасно разбиты. На самом деле, они работают отлично, но наши простые смертные мозги не могут рассматривать полную глубину прототипов Perl.

Предполагается, что они позволят вам вызывать пользовательскую функцию, как если бы она была встроенной функцией, но как они работают, это очень запутанно. См. Perldoc persub для того, как они работают (и не работают).

Некоторое время было какое-то движение, чтобы удалить круглые скобки из вызовов функций Perl, и я предполагаю, что в некоторых случаях удаление посторонних круглых скобок может сделать код более легким для чтения. Однако это крошечное улучшение недостаточно велико, чтобы преодолеть подводные камни прототипирования.

Вы определенно смотрите на рамки прототипирования. Фактически, ваш код на самом деле довольно запутанный, и добавление круглых скобок улучшило бы его читаемость. Да, я знаю, что это не твоя цель. Ваша цель - подумать о прототипировании Perl, пока вы не станете одним с Ларри Уолл. Я ценю вашу храбрость. Я экспериментировал с прототипированием, пока я не вошел в мою спальню, не хлопнул дверью и отказался выходить до ужина. Мне потребовались годы психотерапии и интенсивного питья, чтобы преодолеть мой опыт с прототипом Perl. Даже сегодня я буду плакать неконтролируемо, когда увижу \@@.

Perl 6 должен сделать все лучше. К сожалению, Perl 6 работает дольше, чем Duke Nukem Forever.

Незначительное преувеличение. Duke Nukem был фактически анонсирован в 1997 году, а Perl 6 был объявлен в 2000 году, поэтому у Duke Nukem фактически было около трех лет на Perl 6. Но тогда Герцог У Nukem есть дата выхода (июнь 2011 г.), что больше похоже на Perl 6.

Хорошо, хватит хватать. Вероятно, вам лучше обратиться за помощью к Perlmonks. Это то, где гулят гуру Перла. Вероятно, они могут объяснить все, что происходит с вашей программой, и почему это делает именно то, что нужно.

Дэвид Вайнтрауб

perl -e 'print "Еще один второй уровень Perl-хакера\n";'


ДОПОЛНЕНИЕ

Кажется, что намного больше, чем все, что вы когда-либо хотели узнать о прототипах в Perl, было перенесено в Perl Monks. Это статья, которая объяснит, почему ваши прототипы ведут себя как ожидалось.

Ответ 2

Это похоже на ошибку, но что вы ожидали?

Проиграв немного больше, Perl, похоже, использует какой-то извращенный интеллект.

test blah 1 2 

терпит неудачу, потому что 2 рассматривается как нерелевантность.

Итак, "blah 1" передает проверку для функции с 1 параметром, но тогда обработка glob не подбирает ее. Использование скалярного прототипа делает то, что вы ожидаете.

sub test (*) {print "[@_]\n"} 

==> blah got 1

Я также проверил, было ли возможно больше параметров...

sub test(*) { print "[$_[0] $_[1]]\n" }

бомбы, поскольку $_ [1] не существует.