Почему добавление методов к типу отличается от добавления sub или оператора в perl6? - PullRequest
16 голосов
/ 06 мая 2019

Предоставление подпрограмм / процедур, доступных для повторного использования, является одной из основных функций модулей, и я бы сказал, что это фундаментальный способ компоновки языка и, следовательно, эффективности со временем программиста:

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

# your module
class Foo {
    has $.id;
    has $.name;
}

# my module
sub foo-str(Foo:D $f) is export {
    return "[{$f.id}-{$f.name}]"
}

# someone else using yours and mine together for profit
my $f = Foo.new(:id(1234), :name("brclge"));
say foo-str($f);

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

Учитывая это, я нахожу очень странным, что у нас нет аналогичного механизма для методов, см. Например. обсуждение на Как добавить метод к существующему классу в Perl 6? , тем более что perl6 - такой язык, удовлетворяющий методам. Если я хочу расширить использование существующего типа, я бы хотел сделать это в том же стиле, в котором был написан исходный модуль. Если в Int есть .is-prime, у меня должна быть возможность добавить .И полу-премьер, верно?

Я читал обсуждение по ссылке выше, но не совсем согласен с аргументом "действие на расстоянии": чем это отличается от меня, когда я экспортирую еще один мульти-сабвуфер из модуля? например, ржавый способ сделать это лексическим изменением (Trait + impl ... for) кажется мне довольно гигиеничным и очень бы соответствовал подходу оператора выше.

Более интересным (по крайней мере для меня), чем техническими аспектами, является вопрос, если проектирование языка: разве способность предоставлять новые глаголы (подвиги, операторы, методы) для существующих существительных (типов) не является основной целью при разработке языка как perl6? Если это так, то почему это относится к методам по-другому? И если он по-разному относится к ним по понятной причине, не означает ли это, что мы используем путь ко многим несоставимым методам в качестве существительных, где вместо них следует использовать подпрограммы?

1 Ответ

18 голосов
/ 07 мая 2019

С точки зрения языкового дизайна все сводится к простому вопросу: на каком языке мы говорим?В Perl 6 это вопрос, который мы всегда стараемся прояснить.

Понятие единиц текущий язык в Perl 6 полностью определено в терминах лексической области видимости.Суб декларации ограничены лексической областью.Когда мы импортируем символы из модуля, включая дополнительные multi кандидатов, они имеют лексическую область.Когда мы выполняем языковые настройки, такие как введение новых операторов, они имеют лексическую область.Глаголы в нашем текущем языке - то есть вызовы подпрограмм - это глаголы с лексическим определением.(Операторы - это просто sub вызовы с более интересным синтаксическим анализом.) Поскольку лексические области видимости закрываются в конце времени компиляции, компилятор имеет полное представление о текущем языке.Вот почему вспомогательные вызовы к несуществующим sub s или ссылки на необъявленные переменные обнаруживаются и сообщаются во время компиляции, а также при некоторой базовой проверке типов во время компиляции;будущие версии Perl 6, вероятно, расширят набор ожидаемых проверок во время компиляции.Текущий язык - это статическая ранняя часть Perl 6.

Напротив, вызов метода - это глагол, который должен интерпретироваться в языке целевого объекта .Это динамическая часть с поздним связыванием в Perl 6. Хотя самым непосредственным результатом этого является типичный полиморфизм, встречающийся в различных формах в реализациях ОО, благодаря метапрограммированию даже способ интерпретации глагола истощаетсядля захвата.Например, monitor получит блокировку, в то время как он интерпретирует глагол и освободит его впоследствии.Другие объекты могли быть построены на основе других вещей, кроме кода Perl 6 , и поэтому интерпретация глагола не означает вызова кода, написанного как метод Perl 6.Или код может быть где-то по сети.Кто знает?Ну, конечно, не вызывающий, и в этом суть, а также сила и риск позднего связывания.

Ответ Perl 6 на «Я хочу расширить диапазон глаголов, которые я могу использовать с этим объектом»в моем текущем языке "очень просто: используйте возможности языка, которые относятся к расширению текущего языка!Существует даже специальный синтаксис $obj.&foo, который позволяет определить глагол foo на текущем языке - путем записи sub - и затем вызывать его так, как если бы это был метод объекта.Тем не менее, небольшое синтаксическое различие позволяет читателю - и компилятору - понять, что происходит и какой язык определяет этот глагол.

Благодаря использованию augment это возможно расширить язык, определенный некоторыми типами объектов.Тем не менее, это редко лучший способ сделать что-либо, учитывая, что он будет иметь глобальный эффект, а также разбросать определение языка объекта.

Многое из того, что мы делаем в программировании, касается построения языков.Я не имею в виду новый синтаксис;большинство наших новых языков - даже на языке, открытом для мутаций, как Perl 6, - это просто существительные и глаголы, определенные с использованием стандартных языковых функций.Однако в любой нетривиальной программе мы не можем сразу помнить каждую деталь каждого языка.Когда я иду в ресторан и заказываю шницель, я не знаю, как заказ будет доставлен на кухню, как будет выглядеть кухня, будет ли шницель выбит, панирован и готовится по требованию или просто подается из(надеюсь, не слишком устаревший) тайник с готовыми шницелями.У кухни и меня достаточно общего смысла, чтобы сделать правильные вещи, но я не знаю, как они точно отреагируют на мою просьбу, и им не нужно знать, что я сделаю в это время.Такое мышление признается самим ОО - по крайней мере, когда мы полностью его принимаем - и в более широком масштабе - такими понятиями, как ограниченный контекст, как это найдено в доменно-управляемом дизайне.

Таким образом, Perl 6 пытается помочь нам сохранять ясность в наших языках: знать, что есть в нашем текущем языке, и что мы выражаем с ограниченным пониманием. Это различие кодируется различием sub / method, которое также оказывается разумным местом для статического / динамического различия.

...