Raku Rebless больше не работает с унаследованными классами - PullRequest
9 голосов
/ 21 января 2020

Код, приведенный в этой теме, больше не работает: Как я могу перебить объект в Perl 6?

Я написал этот кусок кода в прошлом году, и он работал тогда. Теперь это не так:

class Person { ; }
class Woman is Person { ; }
my $tom = Person.new;
my $lisa = Woman.new;

say $tom.^name;  # -> Person
say $lisa.^name; # -> Woman

Metamodel::Primitives.rebless($tom, Woman);
# -> New type Woman for Person is not a mixin type

Сообщение об ошибке не имеет смысла, так как предполагается, что оно работает с унаследованными классами. По крайней мере, это было.

Документация не полезна; https://docs.raku.org/routine/rebless

Ответы [ 3 ]

11 голосов
/ 22 января 2020

предполагается, что он работает с унаследованными классами

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

До недавнего времени он не был частью набора тестов спецификации языка - и когда он это делал стать частью этого, он уже имел свою нынешнюю, более ограничительную семантику. Его ограничения важны с точки зрения производительности: когда мы знаем, что тип не является тем, который может быть целью операции mixin, мы можем JIT-компилировать доступ к атрибуту этого объекта во что-то гораздо более простое (мы заплатили дополнительный условный переход на доступ к каждому атрибуту до изменения, и теперь его нужно платить только за целевые типы mixin).

Можно изменить исходную программу для работы, используя MOP для создания класса. На самом деле следующее не совсем оригинальная программа; Я сделал небольшую настройку, чтобы показать, как можно предоставлять методы в подклассе в качестве анонимной роли, чтобы избежать слишком большого количества шаблонов MOP.

class Person { method m() { "person" } }
constant Woman = do {
    my \w = Metamodel::ClassHOW.new_type(:is_mixin, :name<Woman>);
    w.^add_parent(Person);
    w.^add_role(role { method m() { "woman" } });
    w.^compose()
}
my $tom = Person.new;
my $lisa = Woman.new;

say $tom.^name;  # -> Person
say $lisa.^name; # -> Woman

say $tom.m; # person
Metamodel::Primitives.rebless($tom, Woman);
say $tom.m; # woman

Хотя это наиболее семантически прямое исправление для В оригинальной программе есть более короткий путь: используйте оператор but для объекта типа Person, чтобы создать тип mixin и вернуть его, а затем просто настроить его по своему вкусу:

class Person { method m() { "person" } }
constant Woman = Person but role { method m() { "woman" } }
BEGIN Woman.^set_name('Woman');

my $tom = Person.new;
my $lisa = Woman.new;

say $tom.^name;  # -> Person
say $lisa.^name; # -> Woman

say $tom.m;
Metamodel::Primitives.rebless($tom, Woman);
say $tom.m;

В любом случае это только на одну строку больше оригинала.

5 голосов
/ 21 января 2020

См. Ответ jnthn для авторитетной дискуссии о том, что именно произошло с rebless и что с этим делать.

это сработало ... Сейчас нет ... Сообщение об ошибке не ' не имеет смысла ... предполагается, что он работает с унаследованными классами ... По крайней мере, так было ... Документация бесполезна

Этот (очень длинный!) ответ стоит прочитать для тех, кто заинтересован в дальнейшем обсуждении принципов и практики подхода TDD, который лежит в основе работы над языком программирования Raku и связанными с ним артефактами, такими как компилятор Rakudo и docs.raku.org content.

Этот ответ структурирован как конкретные c ответы на конкретные части исходного вопроса Арне и комментарии, которые они написали в ответ на более раннюю версию этого ответа. Мое намерение состояло в том, чтобы сделать его более полезным для Арне, и, надеюсь, все еще полезным для других.

Арне: Код, приведенный в этой теме, больше не работает: Как мне перебросить объект в Раку?

Я обновил принятый ответ на эту SO, чтобы связать ее с этой SO.

Арне: Я написал этот кусок кода в прошлом году, и тогда он работал. Теперь это не

Соответствующее изменение обсуждалось в коммите в апреле 2019 года , в котором jnthn писал:

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

В комментарии 11 дней * go закрытие вопроса rakudo GH "Кажется, что использование нестандартного типа больше не работает" , он написал:

Вам нужно будет организовать передачу именованного аргумента is_mixin в ClassHOW.new_type ... Нет способа сделать это с помощью синтаксиса класса, поэтому должен быть целевой тип rebless: также собран с использованием MOP.

(Нажмите на ссылку выше для заметок о том, как сделать то, что он предлагает.)

Эта проблема также обсуждается немного дальше в it сработало ... вдруг не ... документация ... должна документировать секцию вызова ниже.

Арне: предполагается работать с унаследованные классы. По крайней мере, это было.

roast - r хранилище o f a ll s pe c t ests - определяет, что должен делать код Raku. ( st из roa st можно читать как s в противоположность t o s.)

В еще одно сообщение за апрель 2019 года jnthn писал:

Не было никакого предыдущего spe c для Metamodel::Primitives.rebless. Я добавил этот тест , так что теперь есть. Это означает, что теперь есть какое-то определение того, что можно ожидать.

Тот факт, что поведение Ракудо определяется исполняемым набором тестов, является фундаментальной частью подхода @ Larry к обеспечению Раку ведет себя надежно [1] и имеет глубокие последствия [2] .

Влияние этого изменения на широко используемый модуль

Вот Снимок влияния этого изменения, разворачивающегося для популярного модуля Inline :: Perl5.

В апреле 2019 года niner открыл вопрос о GH в стиле rakudo, влияющий на Inline::Perl5, и я Выделены некоторые основные моменты обмена между niner и jnthn ниже.

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

niner: TBH, что я делаю здесь, вероятно, всегда был ки и неясно ... Может даже быть так ... Я могу избавиться от [этого] ... Было бы неплохо, хотя бы поддерживать уже развернутые версии Inline :: Perl5 в рабочем состоянии.

jnthn: Для Metamodel::Primitives.rebless не было никакого предыдущего спецэффекта c. Я добавил [a] spectest, так что теперь есть. Это означает, что теперь есть какое-то определение того, что можно ожидать, и какой Inline :: Perl5 может положиться.

Поскольку неизвестные именованные параметры игнорируются, но :mixin не требовалось в предыдущих версиях Rakudo, то можно было бы сделать новый релиз Inline :: Perl5, который может работать как с предыдущими версиями Rakudo, так и с будущими, так что, по крайней мере, может быть бэк-компат.

Я не думаю, что есть какие-либо способ работы вещей для существующих версий Inline :: Perl5 ...

niner: К сожалению, передача :mixin в этом случае не помогает, так как выплата производится на подклассе тот, что создан с помощью Metamodel::Primitives.create_type. В подклассе используется обычный Perl6::ClassHOW.

Я работаю над крупным рефакторингом, чтобы сначала избавиться от взлома с помощью Rebless. Я снова открываю эту проблему, чтобы менеджер выпусков знал, что не существует Inline :: Perl5 для кандидата на выпуск rakudo.

jnthn: Вы создаете этот класс с помощью MOP? Вы можете передать :is_mixin в Perl6::ClassHOW.new_type, если это так.

niner: Нет, это для этой ситуации: class Bar is Foo { }

Помощь с документами

В комментарии ниже этого ответа вы написали:

Я могу помочь с частью документации

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

, если это поможет

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

Фундаментальные ограничения на содержание docs.raku.org

Большая часть причины, по которой я написал остальную часть этого очень обширного ответа на такой, казалось бы, простой вопрос, и восстановил его после первоначального удаления, как только Джонатан ответил на него, - это обсудил принципы и практику подхода TDD, который лежит в основе работы над языком программирования Raku и связанными с ним артефактами такие как компилятор Rakudo и docs.raku.org content.

Aiui, желаемая связь между тем, как вещи должны работать в Raku, и как они на самом деле работают в Rakudo, и как все должно быть задокументировано на docs.raku.org сводится к:

  • Eve rything ДОЛЖЕН считаться вечно подчиненным фундаментальной природе волонтерского проекта; и в рамках этого ограничения:

  • Поведение в roast ДОЛЖНО быть задокументировано, а другое поведение НЕ ДОЛЖНО.

(Учитывая доступное время, интерес и согласие добровольцев, иногда делаются исключения для документирования поведения Rakudo QA'd, не покрытого жарким. В текущей практике это, кажется, означает поведение версии Rakudo в выпущенной версии. Rakudo Star.)

Бесполезная документация

Документация бесполезна

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

документация была бесполезной [в 2018 году]

Это совсем другое утверждение .

В то время не было жареной записи, охватывающей rebless.

Если страница docs.raku.org на rebless содержала , то она описывала свое поведение следующим образом: был в 2018 году, тогда это было бы хуже, чем бесполезное , потому что это неправильно указывало бы на то, что текущее поведение было поддержано. В действительности у него была возможность сломаться в будущей версии Rakudo без разумной перспективы, что поведение разработчиков в 2018 году будет восстановлено. И действительно, это произошло: его неподдерживаемое поведение с 2018 года действительно сломалось и не было восстановлено.

Итак, учитывая консенсус в отношении того, что принадлежит docs.raku.org, а что нет (см. Выше), самая полезная вещь, которую могла бы сделать его страница rebless, это либо вовсе не документировать rebless, либо, что еще лучше, включить страницу для нее, но убедиться, что она не описывает его поведение. Какова была ситуация: страница действительно существовала; не был непосредственно полезным; и, возможно, это было лучше, чем ничего.

(Легко представить, что дела еще лучше. Например, что если функции документирования страниц содержат процент, отражающий состояние тестового покрытия, связанного с этой функцией, в версии Rakudo в последней Rakudo Star? 0% могли бы сразу подсказать читателю о том, что эта функция не была покрыта жареным. При этом функция do c легко представить , которая собирается реализовать это? Столь же легко представить, что может потребоваться календарный год или более усердной работы и совместной работы для полезной реализации и развертывания, и что люди думают, что другие вещи более важны.)

это сработало ... вдруг не ... документация ... должна была документировать вызов

это сработало

Это было "везение", сработало.

внезапно он больше не работал

Поскольку Rakudo был улучшен.

документация ... s должен документировать вызов

Как объяснено ранее, все текущие консенсус и / или практика работы сообщества: документация ДОЛЖНА документ конкретная версия вызов, а именно roast d поведения для версии Rakudo в последней Rakudo Star; и МОЖЕТ документировать поведение в других версиях.

и не ссылаться на что-то другое

Aiui, текущий консенсус и / или практика работы таковы, что то, что некоторые могут считать "слабым" "делать c вклады, например, краткий, наспех написанный контент и / или ссылки за пределами документации, МОЖЕТ быть представлен, если добровольцы чувствуют необходимость немедленного изменения, чтобы отразить некоторую обеспокоенность, высказанную пользователем (например, этой СО), и «слабое» изменение было бы лучше, чем вообще ничего не делать. Вы, конечно, можете сделать PR, чтобы улучшить его (или отменить его, если вы действительно чувствуете, что изменение настолько «слабое», что ухудшает положение).

ссылка на изменения в 2019.11 - 7 по моим подсчетам месяцы отпуска

(По моим подсчетам это тоже что-то вроде этого, хотя я видел компилятор, претендующий на 2019.03.1 с таким же перерывом в поведении. [3] )

Я думаю, что JJ сделал изменение do c, и он просто неверно истолковал комментарий jnthn о том, как адаптироваться к изменению. В настоящее время я думаю, что это лучше, чем ничего, но с нетерпением жду вашего обновления. :)

Сноски

[1] Следующее было сказано через несколько минут после того, как Ларри впервые объявил о проекте, который привел к Раку в его 2000 "штате речи о луке :

Вопрос: Будут ли у [Раку] спецификации?

Ларри: то, что мы особенно хотим подчеркнуть ... это, пожалуй, не столько [language design] spe c как развивающий наш текущий регрессионный тест ... в проверочный тест того, что язык на самом деле означает и фактически go, исследует все закоулки и говорит: «Это [Raku], это не [Раку] », и тогда у нас фактически есть машиночитаемое spe c. И для меня это на самом деле гораздо важнее, чем то, что говорит словоблудие в читабельном человеке слове.

[2] Конечно, жаркое хорошо работает только для данного пользователя если его тесты в достаточной степени покрывают потребности пользователя. Проблема Арне демонстрирует, как дыры в освещении могут быть удивительными. Для обсуждения этих дыр в том виде, в каком они были в 2018 году, см. О спецификациях, версиях, изменениях и… поломке . Хорошая новость заключается в том, что roast - это просто множество модульных тестов, написанных на Raku для проверки того, что выражения или конструкции с определенными значениями выполняют определенную функцию. Поэтому отдельным лицам или корпорациям легко вносить новые тесты для улучшения охвата тестов. И все это под контролем версий (git), поэтому настраиваемые нижестоящие теги, ветви и ветки жизнеспособны, устойчивы и управляемы. (Действительно, именно так управляются новые языковые версии (Christmas, Diwali, Eid (?) И др. c.).)

[3] I я видел попытку восстановить новый класс, созданный с использованием обычного newclass is oldclass синтаксиса, и работают (на моем ноутбуке) и не работают (на repl.it) с использованием компиляторов, которые утверждают, что быть 2019.03.1. (Предположим, repl.it установил версию исходного кода компилятора или скомпилированный из него двоичный файл, взятый из главной главы вскоре после того, как версия компилятора была обновлена ​​до 2019.03.1, с критическим изменением на месте. Я отмечаю, что repl. он не опубликовал их онлайн-реплан raku - я обнаружил это случайно - так что в этой ситуации нет ничего плохого, но это усилило для меня необходимость в методе $RAKU.compiler.verbose-config, используемом в обработанных / неработающих выходных данных, которые я только что связал.)

0 голосов
/ 02 февраля 2020

Дополнительный вопрос: см. Раклу Ресслесс и несколько классов

...