Пакетно-уточненные имена. Различия (если есть) между Package :: <& var> и Package :: var? - PullRequest
7 голосов
/ 10 июня 2019

Считывая https://docs.perl6.org/language/packages#Package-qualified_names, он описывает подходящие переменные пакета с этим синтаксисом:

Foo::Bar::<$quux>; #..as an alternative to Foo::Bar::quux;

Для справки структура пакета, использованная в качестве примера в документе:

class Foo {
    sub zape () { say "zipi" }
    class Bar {
        method baz () { return 'Þor is mighty' }
        our &zape = { "zipi" };   #this is the variable I want to resolve
        our $quux = 42;
    }
}

На той же странице указано, что этот стиль квалификации не работает для доступа к &zape в пакете Foo :: Bar, указанном выше:

(это не работает с переменной & zape)

Тем не менее, если я попытаюсь:

Foo::Bar::<&zape>;  # instead of   &Foo::Bar::zape;

, это решит просто отлично.

Я неправильно истолковал документ или полностью пропустил поставленную точку?Какая логика стоит за тем, что он «не работает» со ссылочными переменными кода против скаляра, например?

Ответы [ 3 ]

5 голосов
/ 10 июня 2019

Я не знаю различий, но Foo::Bar::<&zape> также можно изменить, чтобы использовать {} вместо <>, который затем можно использовать с чем-то отличным от литералов, например:

my $name = '&zape';
Foo::Bar::{$name}()

или

my $name = 'zape';
&Foo::Bar::{$name}()
4 голосов
/ 10 июня 2019

Нет никаких отличий между Package :: <& var> и & Package :: var.

package Foo { our $var = "Bar" };
say $Foo::var === Foo::<$var>; # OUTPUT: «True␤» 

То же самое для сабов (конечно):

package Foo { our &zape = { "Bar" } };
say &Foo::zape === Foo::<&zape>;# OUTPUT: «True␤»

Что такое документация (несколько сбивает с толку) пытается сказать, что переменные области видимости пакета могут быть доступны только если объявлены с использованием нашего.Есть два zape s, один из них имеет лексическую область видимости (сабы получают лексическую область видимости по умолчанию), поэтому вы не можете получить к ней доступ.Я поднял эту проблему в репозитории документов и постараюсь исправить это как можно скорее.

3 голосов
/ 14 июня 2019

JJ и Мориц предоставили полезные ответы.

Этот нансвер представляет собой еще один шарик воска. За последние несколько дней я написал и отклонил несколько ответов на ваш вопрос. Ни один не был очень полезен. Я не уверен, что это так, но я решил, что наконец-то получил первую версию чего-то, что стоит опубликовать, независимо от ее текущей полезности.

В этом первом выпуске мой ответ - всего лишь серия замечаний и вопросов. Я также надеюсь добавить объяснение моих наблюдений, основанное на том, что я получил от написания кода компилятора, чтобы понять то, что мы видим. (Сейчас я только что записал начало этого процесса как вторую половину этого ответа.)

Различия (если есть) между Package::<&var> против &Package::var?

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

Давайте пройдемся по множеству вариаций, вытянув различия.

say Package::<&var>; # compile-time error: Undeclared name: Package

Итак, на секунду забудьте о бите ::<...>. P6 смотрит на этот Package бит и требует, чтобы это было уже объявленное имя. Это кажется достаточно простым.

say &Package::var; # (Any)

Разница! По какой-то причине в этом втором синтаксисе у P6 нет проблем с тем, что эти два произвольных имени (Package и var) не были объявлены. Кто знает, что он делает с &. И почему это (Any) а не (Callable) или Nil?

Давайте попробуем объявить эти вещи. Во-первых:

my Package::<&var> = { 42 } # compile-time error: Type 'Package' is not declared

OK. Но если мы объявим Package, то ничего не улучшится:

package Package {}
my Package::<&var> = { 42 } # compile-time error: Malformed my

ОК, начните снова с чистого листа, без объявления package. А как насчет другого синтаксиса?:

my &Package::var = { 42 }

Yay. P6 принимает этот код. Теперь для следующих нескольких строк мы примем объявление выше. Как насчет:

say &Package::var(); # 42

\ o / Так можем ли мы использовать другой синтаксис?:

say Package::<&var>(); # compile-time error: Undeclared name: Package

Неа. Кажется, что my не объявил Package с &var в нем. Может быть, он объявил &Package::var, где :: просто является частью имени, но не о пакетах? P6 поддерживает набор «псевдо» пакетов . Один из них LEXICAL:

say LEXICAL::; # PseudoStash.new(... &Package::var => (Callable) ... 

Бинго. Или это так?

say LEXICAL::<&Package::var>(); # Cannot invoke this object
                                # (REPR: Uninstantiable; Callable)

Что случилось с нашим { 42 }?

Хм. Давайте начнем с чистого листа и создадим &Package::var совершенно другим способом:

package Package { our sub var { 99 } }
say &Package::var();   # 99
say Package::<&var>(); # 99

Ничего себе. Теперь, предполагая те строки выше и пытаясь добавить больше:

my Package::<&var> = { 42 } # Compile-time error: Malformed my

Этого следовало ожидать, учитывая нашу предыдущую попытку выше. Как насчет:

my &Package::var = { 42 }   # Cannot modify an immutable Sub (&var)

Теперь все имеет смысл? ;)

Правописание кода компилятора, проверка грамматики

1 Я потратил много времени, пытаясь понять, в чем дело на самом деле , прежде чем смотреть на исходный код компилятора Rakudo . Это сноска, покрывающая мое начальное написание компилятора. Я надеюсь продолжить это завтра и превратить этот ответ в ответ на этих выходных.

Хорошая новость в том, что это просто код P6 - большая часть Rakudo написана на P6.

Плохая новость - знать, где искать. Вы можете увидеть каталог doc, а затем обзор компилятора . Но тогда вы заметите, что обзорный документ почти не затрагивался с 2010 года! Не беспокойся Возможно посты Андрея Шитова помогут вам сориентироваться? Идем дальше ...

В данном случае меня интересует понимание точной природы синтаксиса Package::<&var> и &Package::var. Когда я набираю «синтаксис» в поле поиска репозитория GH, в списке появляется второй файл Грамматика Perl 6 . Бинго.

Теперь приходят ужасные новости. Файл грамматики Perl 6 имеет 6K LOC и выглядит очень пугающим. Но я считаю, что все это имеет смысл, когда я хладнокровен.

Далее мне интересно, что искать на странице. :: сетей 600+ матчей. Хм. ::< - это всего лишь 1, но это сообщение об ошибке. А в чем? В token morename. Глядя на это, я вижу, что это не актуально. Но '::' около начала токена - это просто билет. Поиск по странице '::' дает 10 совпадений. Первые 4 (от начала файла) - больше сообщений об ошибках. Следующие два находятся в указанном выше morename токене. Осталось 4 матча.

Следующий появляется четверть через token term:sym<name>. Имя". .oO (Undeclared name: Package Так может это актуально?)

Далее token typename. «Типовое имя». .oO (Type 'Package' is not declared Так может это тоже актуально?)

token methodop. Определенно не актуально.

Наконец token infix:sym<?? !!>. Нет.

...