Вопрос:

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

perl

5388 просмотра

4 ответа

58172 Репутация автора

(Предположим на 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 @_; }

Аналогично, саб без аргументов, таких как:

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в верхней части сценария.
  • Позвоните special_printпосле под декларации.

У меня вопрос, почему это специальное лечение? Если я могу использовать подпрограмму глобально в скрипте, почему я не могу использовать ее так, как мне хочется? Есть ли логика для subреализации таким образом?

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

Автор: TLP Источник Размещён: 13.05.2011 01:36

Ответы (4)


6 плюса

93650 Репутация автора

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

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

Автор: Eugene Yarmash Размещён: 13.05.2011 01:47

-2 плюса

3889 Репутация автора

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

Ученый-компьютерщик : грамматика языка должна быть максимально простой и понятной.

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

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

Автор: edgar.holleis Размещён: 13.05.2011 02:24

17 плюса

89519 Репутация автора

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

В Perl много грубого и грубого из пяти разных версий языка. 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, чтобы обойти это ограничение. Используйте use subsили предварительно объявите пустую подпрограмму. Не используйте прототипы.

Автор: David W. Размещён: 13.05.2011 02:45

33 плюса

36275 Репутация автора

Решение

Я думаю, что вам не хватает того, что 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 была полная обратная совместимость. Скрипт, который работает в Perl 1, все еще работает в Perl 5. Из-за этого невозможно изменить правила, связанные с анализом голых слов.

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

Автор: Eric Strom Размещён: 13.05.2011 03:14
Вопросы из категории :
32x32