Это ошибка с глобальным прототипом Perl? - PullRequest
16 голосов
/ 08 апреля 2011

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

Учитывая следующий код:

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 полностью удален из дерева операций.

Так что мой вопрос, считают ли другие это поведение ошибкой?Документировано ли поведение где-нибудь?Если это ошибка, стоит ли ее исправлять?

Ответы [ 2 ]

3 голосов
/ 05 мая 2011

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

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

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

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

Предполагается, что Perl 6 сделает все лучше. К сожалению, Perl 6 находится в разработке дольше, чем Duke Nukem Forever .

Небольшое преувеличение. Duke Nukem был фактически анонсирован в 1997 году, в то время как Perl 6 был объявлен в 2000 году, так что у Duke Nukem на Perl 6 было около трех лет. что Perl 6 имеет.

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

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

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


ДОПОЛНЕНИЕ

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

0 голосов
/ 27 апреля 2011

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

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

test blah 1 2 

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

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

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

==> blah got 1

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

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

бомбы как $ _ [1]не существует.

...