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

Почему скобка необязательна только после объявления sub?

(предположим use strict; use warnings; по всему этому вопросу.)

Я изучаю использование sub.

sub bb { print @_; }
bb 'a';

Это работает так, как ожидалось. Скобки являются необязательными, например, со многими другими функциями, такими как print, open и т.д.

Однако это вызывает ошибку компиляции:

bb 'a';
sub bb { print @_; }

String found where operator expected at t13.pl line 4, near "bb 'a'"
        (Do you need to predeclare bb?)
syntax error at t13.pl line 4, near "bb 'a'"
Execution of t13.pl aborted due to compilation errors.

Но это не так:

bb('a');
sub bb { print @_; }

Аналогично, sub без args, например:

special_print;
my special_print { print $some_stuff }

Вызывает эту ошибку:

Bareword "special_print" not allowed while "strict subs" in use at t13.pl line 6.
Execution of t13.pl aborted due to compilation errors.

Способы устранения этой конкретной ошибки:

  • Поместите и до подзаголовка, например. &special_print
  • Поместить пустую скобку после подзаголовка, например. special_print()
  • Predeclare special_print с sub special_print в верхней части script.
  • Вызов special_print после декларации sub.

Мой вопрос: почему это специальное лечение? Если я могу использовать суб-глобально внутри script, почему я не могу использовать его так, как хочу? Существует ли логика для sub таким образом?

ETA: Я знаю, как я могу это исправить. Я хочу знать логику этого.

4b9b3361

Ответ 1

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

В Perl синтаксис sub NAME для объявления подпрограммы эквивалентен следующему:

sub name {...}   ===   BEGIN {*name = sub {...}}

Это означает, что синтаксис sub NAME имеет эффект времени компиляции. Когда Perl анализирует исходный код, он работает с текущим набором объявлений. По умолчанию набор - встроенные функции. Поскольку Perl уже знает об этом, он позволяет опустить скобки.

Как только компилятор попадает в блок BEGIN, он компилирует внутреннюю часть блока, используя текущий набор правил, а затем сразу же выполняет блок. Если что-либо в этом блоке изменяет набор правил (например, добавление подпрограммы к текущему пространству имен), эти новые правила будут действовать для остальной части синтаксического анализа.

Без предопределенного правила идентификатор будет интерпретироваться следующим образом:

bareword       ===   'bareword'   # a string
bareword LIST  ===   syntax error, missing ','
bareword()     ===   &bareword()  # runtime execution of &bareword
&bareword      ===   &bareword    # same
&bareword()    ===   &bareword()  # same

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

Если предварительно указано какое-либо из следующего:

sub bareword;
use subs 'bareword';
sub bareword {...}
BEGIN {*bareword = sub {...}}

Затем идентификатор будет интерпретироваться следующим образом:

bareword      ===   &bareword()     # compile time binding to &bareword
bareword LIST ===   &bareword(LIST) # same
bareword()    ===   &bareword()     # same
&bareword     ===   &bareword       # same
&bareword()   ===   &bareword()     # same

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

Что касается того, почему за всем этим, Perl имеет много наследия. Одной из целей разработки Perl была полная обратная совместимость. A script, который работает в Perl 1, все еще работает в Perl 5. Из-за этого изменить правила, связанные с разбором дескрипторов, невозможно.

Тем не менее вам будет трудно найти язык, который будет более гибким в том, как он позволяет вам вызывать подпрограммы. Это позволяет вам найти метод, который лучше всего подходит для вас. В моем собственном коде, если мне нужно вызвать подпрограмму, прежде чем она была объявлена, я обычно использую name(...), но если эта подпрограмма имеет прототип, я буду называть ее как &name(...) (и вы получите предупреждение) подпрограмму слишком рано, чтобы проверить прототип "если вы не называете его таким образом".

Ответ 2

Лучший ответ, который я могу придумать, - это то, как написан Perl. Это не удовлетворительный ответ, но, в конце концов, это правда. Perl 6 (если он когда-либо появится) не будет иметь этого ограничения.

Perl имеет много crud и craft из пяти разных версий языка. Perl 4 и Perl 5 сделали некоторые существенные изменения, которые могут вызвать проблемы с более ранними программами, написанными свободно распространяемым образом.

Из-за долгой истории и различных способов использования и работы Perl Perl может быть трудно понять, что происходит. Когда у вас есть это:

b $a, $c;

Perl не знает, является ли b строкой и является просто голосом (что разрешено в Perl 4) или b является функцией. Если b является функцией, она должна храниться в таблице символов, когда остальная часть программы анализируется. Если b не является подпрограммой, вы не должны помещать ее в таблицу символов.

Когда компилятор Perl видит это:

b($a, $c);

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

Когда вы предварительно объявляете свою функцию, Perl может это увидеть:

sub b;   #Or use subs qw(b); will also work.

b $a, $c;

и знать, что b является функцией. Он может не знать, что делает функция, но теперь есть запись таблицы символов для функции b.

Одной из причин для Perl 6 является удаление большей части багажа, оставшегося от старых версий Perl, и удаление таких странных вещей.

Кстати, никогда не используйте Perl Prototypes, чтобы обойти это ограничение. Используйте use subs или предварите пустую подпрограмму. Не используйте прототипы.

Ответ 3

Скобки являются необязательными, только если подпрограмма была предварительно определена. Это описано в perlsub.

Perl должен знать во время компиляции, является ли одно слово именем подпрограммы или строковым литералом. Если вы используете круглые скобки, Perl угадает, что это имя подпрограммы. В противном случае вам необходимо заранее предоставить эту информацию (например, используя subs).

Ответ 4

Причина в том, что Ларри Уолл - лингвист, а не компьютерный ученый.

Компьютерный ученый. Грамматика языка должна быть максимально простой и понятной.

  • Избегает сложности в компиляторе
  • Устраняет источники двусмысленности

Ларри Уолл. Люди работают иначе, чем компиляторы. Язык должен служить программисту, а не компилятору. См. Также план Ларри Стена из трех достоинств программиста.