Является ли это дефектом дизайна, что подлодки Perl не лексически охвачены?

{
  sub a {
    print 1;
  }
}
a;

Ошибка, не так ли?

a не должен быть доступен снаружи.

Работает ли он в Perl 6 *?

* Извините, что я еще не установил его.

Ответ 1

Вы спрашиваете, почему sub видимо вне блока? Если это так, то из-за того, что ключевое слово sub времени компиляции помещает sub в пространство имен main (если вы не используете ключевое слово package для создания нового пространства имен). Вы можете попробовать что-то вроде

{
  my $a = sub {
    print 1;
  };
  $a->(); # works
}
$a->(); # fails

В этом случае ключевое слово sub не создает sub и помещает его в пространство имен main, а вместо этого создает анонимную подпрограмму и сохраняет ее в переменной с лексической областью. Когда переменная выходит за пределы области видимости, она больше не доступна (обычно).

Чтобы узнать больше, perldoc perlsub

Кроме того, знаете ли вы, что вы можете проверить, как Perl-парсер видит ваш код? Запустите perl с флагом -MO=Deparse, как в perl -MO=Deparse yourscript.pl. Ваш исходный код анализирует как:

sub a {
    print 1;
}
{;};
a ;

Сначала скомпилируется sub, затем блок запускается без кода в нем, затем вызывается a.

Для моего примера в Perl 6 см. Успех, Отказ. Обратите внимание, что в Perl 6 разыменование . не ->.

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

Ответ 2

В Perl 6 субсайты действительно лексически охвачены, поэтому код вызывает ошибку (как уже указывали несколько человек).

Это имеет несколько интересных последствий:

  • Вложенные названные подпрограммы работают как надлежащие закрытия (см. также: предупреждение "не останется общедоступным" в perl 5)
  • импорт субмарин из модулей работает в лексических областях
  • встроенные функции предоставляются во внешней лексической области ( "настройка" ) вокруг программы, поэтому переопределение выполняется так же легко, как объявление или импорт функции с тем же именем
  • поскольку lexpads неизменяемы во время выполнения, компилятор может обнаруживать вызовы неизвестных подпрограмм во время компиляции (niecza делает это уже, Rakudo только в ветке "оптимизатор" ).

Ответ 3

Подпрограммы - это область с областью действия, но не с областью охвата.

#!/usr/bin/perl
use strict;
use warnings;

package A;
sub a {
    print 1, "\n";
}
a();
1;

package B;
sub a {
    print 2, "\n";
}
a();
1;

Ответ 4

Именованные подпрограммы в Perl создаются как глобальные имена. В других ответах показано, как создавать лексические подпрограммы, назначая анонимный субрежим лексической переменной. Другой вариант - использовать переменную local для создания поддиапазона с динамической областью.

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

use strict;
use warnings;
sub test_sub {
    print "in test_sub\n";
    temp_sub();
}

{
    local *temp_sub = sub {
        print "in temp_sub\n";
    };
    temp_sub();
    test_sub();
}
test_sub();

Это должно печатать

in temp_sub
in test_sub
in temp_sub
in test_sub
Undefined subroutine &main::temp_sub called at ...

Ответ 5

Если вы видите компиляцию кода, запустите и распечатаете "1", вы не будете испытывать ошибку.

Кажется, вы ожидаете, что подпрограммы будут только вызываемыми внутри лексической области, в которой они определены. Это было бы плохо, потому что это означало бы, что нельзя будет вызывать подпрограммы, определенные в других файлах. Может быть, вы не понимали, что каждый файл оценивается в своей лексической области? Это позволяет использовать

my $x = ...;
sub f { $x }

Ответ 6

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

Вот ссылка на соответствующую документацию. Опять же, это очень экспериментально, его нельзя использовать для производственного кода по двум причинам:

  • Возможно, это еще не реализовано.
  • Он может быть удален без предупреждения

Так что играйте с этой новой игрушкой, если хотите, но вас предупредили!

Ответ 7

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

Лексическая область была добавлена ​​в Perl 5, но в качестве дополнительной функции вам всегда нужно указать ее конкретно. С этим выбором дизайна я полностью согласен: обратная совместимость важна.