В чем разница между моим классом и нашим классом в Raku (perl6)?

Я прочитал спецификацию, но все еще не понимаю, чем my class отличается от [our] class. Какие различия и когда использовать?


person teodozjan    schedule 18.11.2015    source источник


Ответы (3)


Как и в случае с переменными, my связывает имя лексически, тогда как our дополнительно создает запись в окружающем пакете.

module M {
    our class Foo {}
    class Bar {} # same as above, really
    my class Baz {}
}

say M::Foo; # ok
say M::Bar; # still ok
say M::Baz; # BOOM!

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

person Christoph    schedule 18.11.2015
comment
А как насчет роли Rational, которая является общедоступной и экспортируется? github.com/rakudo/rakudo/ - person teodozjan; 19.11.2015
comment
@teodozjan: Его не нужно публиковать или экспортировать, потому что это часть «настройки». Весь код, который вы пишете, неявно окружен внешней лексической областью видимости, которая содержит основные встроенные функции, такие как Rational - person Christoph; 19.11.2015

Объявление области my подразумевает лексическую область видимости: после объявления символ становится видимым для кода в текущем наборе фигурных скобок. Таким образом, мы склонны называть область в фигурных скобках лексической областью. Например:

sub foo($p) {
    # say $var;       # Would be a compile time error, it's not declared yet
    my $var = 1;
    if $p {
        $var += 41;   # Inner scope, $var is visible
    }
    return $var;      # Same scope that it was declared in, $var is visible
}
# say $var;           # $var is no longer available, the scope ended

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

  • Программист (как из-за их собственных рассуждений о программе, так и потому, что можно обнаружить больше ошибок и сообщить о них, когда вещи имеют лексическую область видимости)
  • Компилятор (лексическая область видимости позволяет проще и лучше оптимизировать)
  • Инструменты, такие как IDE (анализ и рассуждения о вещах с лексической областью намного более управляемы)

На раннем этапе разработки языка, который впоследствии стал Raku, подпрограммы по умолчанию не имели лексической области видимости (и имели our область видимости, как в Perl), однако было решено, что лексическая область видимости является лучшим вариантом по умолчанию. Выполнение вызовов подпрограмм всегда пытается разрешить символ с лексической областью видимости, что означает, что можно было сообщить о необъявленных подпрограммах во время компиляции. Кроме того, набор символов в лексической области видимости фиксируется во время компиляции, и в случае декларативных конструкций, таких как подпрограммы, подпрограмма привязывается к этому символу только для чтения. Это также позволяет такие вещи, как разрешение множественной отправки во время компиляции, проверка аргументов во время компиляции и т. Д. Вероятно, что в будущих версиях языка Raku будет указываться возрастающее количество проверок во время компиляции для элементов программы с лексической областью видимости.

Итак, если лексическая область видимости настолько хороша, почему существует область видимости our (также известная как пакет)? Короче, потому что:

  1. Иногда мы хотим делиться вещами шире, чем в пределах заданной лексической области. Мы могли бы просто объявить все лексическим, а затем пометить вещи, которыми мы хотим поделиться с is export, но ...
  2. Как только мы дойдем до использования множества разных библиотек, попытка всего экспортировать вещи в единую лексическую область видимости потребителя, скорее всего, приведет к множеству конфликтов.

Пакеты позволяют размещать символы в именах. Например, если я хочу использовать клиенты Cro как для HTTP, так и для WebSockets в одном коде, я могу с радостью использовать оба, и называть их Cro::HTTP::Client и Cro::WebSocket::Client соответственно.

Пакеты вводятся деклараторами пакетов, такими как class, module, grammar и (с оговорками) role. Объявление our выполнит установку во вложенной конструкции пакета.

Эти пакеты в конечном итоге существуют в пакете верхнего уровня с именем GLOBAL, что вполне уместно, поскольку они фактически видны глобально. Если мы объявляем переменную с our-областью видимости, это, таким образом, глобальная переменная (хотя, будем надеяться, с пространством имен), о которой было написано достаточно, чтобы мы знали, что нам следует задуматься и задуматься, является ли глобальная переменная лучшим решением API (потому что , в конечном счете, все, что становится видимым через GLOBAL, является решением API).

Однако что-то действительно становится немного размытым, так это то, что у нас могут быть лексические пакеты. Это пакеты, которые не устанавливаются в GLOBAL. Я считаю их чрезвычайно полезными при программировании объектно-ориентированного программирования. Например, у меня могло быть:

# This class that ends up in GLOBAL...
class Cro::HTTP::Client {
    # Lexically scoped classes, which are marked `my` and thus hidden
    # implementation details. This means I can refactor them however I
    # want, and never have to worry about downstream fallout!
    my class HTTP1Pipeline {
        # Implementation...
    }
    my class HTTP2Pipeline {
        # Implementation...
    }

    # Implementation...
}

Лексические пакеты также могут быть вложенными и содержать переменные с областью видимости our, однако они не становятся видимыми глобально (если мы каким-то образом не решим их утечь).

Различным элементам программы Raku приписана область действия по умолчанию:

  • Подпрограммы по умолчанию имеют лексическую (my) область видимости
  • По умолчанию для методов используется область видимости has (видна только при отправке метода)
  • Тип (класс, роль, грамматика, подмножество) и объявления модуля по умолчанию для области видимости пакета (our)
  • Константы и перечисления по умолчанию соответствуют области действия пакета (our)

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

Лично я не решаюсь сделать что-то более видимым, чем настройки языка по умолчанию, однако я часто делаю их менее заметными (например, my для констант, предназначенных для внутреннее использование и классы, которые я использую для структурирования деталей реализации). Когда я мог что-то сделать, выставив переменную с our областью видимости в глобально видимом пакете, я по-прежнему часто предпочитаю делать ее с областью видимости my и предоставлять sub (экспортируется) или method (отображается в силу того, что находится в области видимости пакета. class), чтобы контролировать доступ к нему, чтобы купить себе гибкость в будущем. Я считаю, что делать неправильный выбор сейчас - это нормально, если я дал себе пространство, чтобы сделать его правильнее в будущем, не причиняя никому неудобств. :-)

В итоге:

  • Используйте my область видимости для всего, что касается деталей реализации
  • Также используйте my область видимости для вещей, которые вы планируете export, но помните, что экспорт помещает символы в единую лексическую область видимости потребителя и рискует столкнуться с конфликтами имен, поэтому будьте внимательны при экспорте особенно общих имен.
  • Используйте our для вещей, которые должны быть разделены, и когда необходимо использовать пространство имен, чтобы избежать конфликтов
  • В любом случае элементы, которые мы больше всего хотели бы использовать по умолчанию в our области видимости, поэтому явное написание our должно дать паузу для размышлений.
person Jonathan Worthington    schedule 05.02.2021

Различие my и our в основном имеет значение при создании таблицы символов. Например:

my $a;           # Create symbol <$a>  at top level
package Foo {    # Create symbol <Foo> at top level
   my  $b;       # Create symbol <$b>  in Foo scope 
   our $c;       # Create symbol <$c>  in Foo scope
}                #           and <Foo::<$c>> at top level

На практике это означает, что все, что our ограничено, легко передается внешнему миру путем добавления префикса к идентификатору пакета ($Foo::c или Foo::<$c> являются синонимами), а все, что my ограничено, не всегда доступно - хотя вы, безусловно, можете предоставить доступ к нему через , например, геттер-подпрограммы.

В большинстве случаев вы захотите использовать my. Большинство переменных просто принадлежат их текущей области действия, и никто не занимается этим. Но our может быть полезен в некоторых случаях:

  • константы, которые не отравляют таблицу символов (именно поэтому использование constant подразумевает область видимости our). Таким образом, вы можете сделать больше перечислений / констант в стиле C, используя package Colors { constant red = 1; constant blue = 2; }, а затем ссылаясь на них как на Colors::red
  • классы или подпрограммы, которые должны быть доступны, но не должны быть экспортированы (или не должны быть из-за перекрытия символов со встроенными или другими модулями). Экспорт символов может быть отличным, но иногда также приятно иметь пространство имен пакета / модуля, чтобы напоминать вам, с чем идет речь. Таким образом, это также хороший способ управлять параметрами во время выполнения с помощью подпрограмм: CoolModule::set-preferences( ... ). (хотя и здесь можно использовать динамические переменные).

Я уверен, что другие прокомментируют другие случаи, когда our будет полезен, но это из моего собственного опыта.

person user0721090601    schedule 04.02.2021