Raku Rebless больше не работает с унаследованными классами

9

Код, приведенный в этом потоке, больше не работает: как я могу восстановить объект в 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

Арне Соммер
источник
Может быть ошибка регрессии. Вероятно, лучше всего сообщить об этом как о проблеме Ракудо.
jjmerelo
Были некоторые изменения в феврале прошлого года: github.com/perl6/nqp/blob/...
jjmerelo
Кроме того, я обновил документацию сноской, указывающей на ответ @jnthn docs.raku.org/type/Metamodel::Primitives . Спасибо, raiph
jjmerelo

Ответы:

11

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

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

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

Можно изменить исходную программу для работы с помощью 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объекта типа, чтобы создать смешанный тип и вернуть его, а затем просто настроить его имя по своему вкусу:

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;

Который в любом случае на одну строчку больше оригинала.

Джонатан Уортингтон
источник
constant Woman = Person but role …Не понимал, что это можно сделать. И, таким образом, кроме BEGINлинии, Raku почти справляется с возможностью создать прототипную парадигму в стиле JS!
user0721090601
Хорошо. Спасибо за объяснение. Я надеюсь, что он найдет свой путь в документации, так как docs.raku.org/routine/rebless довольно бесполезен ... Я скоро обновлю «Beginning Raku».
Арне Соммер
@ user0721090601 Raku поддерживает, цитируя S12: «ОО-программирование на основе классов и прототипов» . Однако, если вы создаете объекты с помощью classключевого слова , то, снова заключая в кавычки S12: «по умолчанию объекты, полученные из, Muподдерживают довольно стандартную модель на основе классов ... bless... вызовы ... процедуры BUILD ... семантика BUILD по умолчанию наследуется от Mu". Подводя итог, я бы сказал, что точнее будет сказать, что Raku поддерживает A) «серьезно искажает даже стандартную OO, основанную на классах болота, всего с помощью пары строк кода» и B) «OO, основанную на прототипах».
raiph
Смотрите raku-musings.com/reblessed.html для моего взгляда на критические изменения.
Арне Соммер
5

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

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

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

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

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

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

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

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

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

В комментарии 11 дней назад, закрыв вопрос Rakudo GH «Rebless для нестандартного типа, похоже, больше не работает» , он написал:

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

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

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

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

жаркий - г epository о еЛ.Л. s PEC т ресы - определяетчто Рака код должен делать. (The ул из ROA ул может быть прочитана как с upposed т о с.)

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

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

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

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

Вот снимок влияния этого изменения на популярный модуль Inline :: Perl5.

В апреле 2019 года Niner открыл вопрос о рахудо GH,Inline::Perl5 и я выделил некоторые основные моменты обмена между Niner и Jnthn ниже.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Основные ограничения на содержание docs.raku.org

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

Во-вторых, желаемая связь между тем, как вещи должны работать в Раку, и тем, как они действительно работают в Ракудо, и тем, как вещи должны документироваться на docs.raku.org, сводится к следующему:

  • Все должны считаться , чтобы всегда быть предметом фундаментального характера проекта волонтеров; и в рамках этого ограничения:

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

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

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

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

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

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

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

В то время не было покрытия для жареного мяса rebless.

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

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

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

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

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

Это была «удача», это сработало.

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

Потому что Ракудо был улучшен.

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

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

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

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

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

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

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

Сноски

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

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

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

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

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

raiph
источник
Я нашел эту статью, когда попытался выяснить, как работает «rebless», так как документация была бесполезна: stackoverflow.com/questions/44486985/… И это сработало. А потом это внезапно перестало работать, и документация все еще была бесполезна. Это все еще так, как следует документировать вызов, а не ссылаться на что-то еще. И ссылка на изменения в 2019.11 по моим подсчетам - 7 месяцев.
Арне Соммер
Я могу помочь с документацией, если это поможет.
Арне Соммер
@ArneSommer Пожалуйста, смотрите новые разделы в моем ответе, начиная с Помощь с документами .
raiph