Raku rebless funktioniert nicht mehr mit geerbten Klassen

9

Der in diesem Thread angegebene Code funktioniert nicht mehr: Wie kann ich ein Objekt in Perl 6 erneut aktivieren?

Ich habe diesen Code letztes Jahr geschrieben und er hat dann funktioniert. Jetzt tut es nicht:

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

Die Fehlermeldung ist nicht sinnvoll, da sie mit geerbten Klassen funktionieren soll. Zumindest war es das.

Die Dokumentation ist nicht hilfreich; https://docs.raku.org/routine/rebless

Arne Sommer
quelle
Könnte ein Regressionsfehler sein. Wahrscheinlich am besten, um es als Rakudo-Problem zu melden.
jjmerelo
Im vergangenen Februar gab es einige Änderungen: github.com/perl6/nqp/blob/…
jjmerelo
Außerdem habe ich die Dokumentation mit einer Fußnote aktualisiert, die auf @jnthn answer docs.raku.org/type/Metamodel::Primitives verweist . Danke, raiph
jjmerelo

Antworten:

11

Es soll mit geerbten Klassen funktionieren

Es sollte nie so allgemein sein. Ich habe diese API entworfen und in erster Linie implementiert, und sie war immer nur als Implementierungsdetail von Mixins gedacht.

Bis vor kurzem war es nicht Teil der Testsuite für Sprachspezifikationen - und als es Teil davon wurde, hatte es bereits seine aktuelle, restriktivere Semantik. Die Einschränkungen sind aus Leistungsgründen wichtig: Wenn wir wissen, dass ein Typ nicht das Ziel einer Mixin-Operation sein kann, können wir Attributzugriffe auf dieses Objekt in etwas viel Einfacheres JIT-kompilieren (wir haben einen zusätzlichen bedingten Schritt bezahlt) jeder Attributzugriff vor der Änderung und muss jetzt nur noch für Mixin-Zieltypen bezahlt werden).

Es ist möglich, das ursprüngliche Programm so zu ändern, dass es funktioniert, indem Sie die Klasse mithilfe der MOP erstellen. In der Tat ist das Folgende nicht ganz das ursprüngliche Programm; Ich habe eine kleine Änderung vorgenommen, um zu zeigen, wie man Methoden in der Unterklasse als anonyme Rolle bereitstellen kann, um zu viel MOP-Boilerplate zu vermeiden.

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

Dies ist zwar die semantisch direkteste Lösung für das ursprüngliche Programm, es gibt jedoch einen kürzeren Weg: Verwenden Sie den butOperator für das PersonTypobjekt, um einen Mixin-Typ zu erstellen und zurückzugeben, und passen Sie den Namen dann einfach nach Ihren Wünschen an:

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;

Das ist sowieso nur eine Zeile mehr als das Original.

Jonathan Worthington
quelle
constant Woman = Person but role …Wusste nicht, dass das möglich ist. Und so BEGINschafft es Raku, abgesehen von der Linie, gerade noch, ein prototypisches Paradigma im JS-Stil zu entwickeln!
user0721090601
OK. Vielen Dank für die Erklärung. Ich hoffe, dass es seinen Weg in die Dokumentation findet, da docs.raku.org/routine/rebless ziemlich nutzlos ist ... Ich werde «Beginning Raku» in Kürze aktualisieren.
Arne Sommer
@ user0721090601 Raku unterstützt unter Angabe von S12: "sowohl klassenbasierte als auch prototypbasierte OO-Programmierung" . Allerdings , wenn Sie konstruieren Objekte , die mit classSchlüsselwort , dann unter Angabe S12 wieder: „standardmäßig von abgeleiteten Objekten Muunterstützen ein ziemlich Standard - Klasse-basiertes Modell ... bless... Anrufe ... BUILD - Routinen ... default BUILD Semantik geerbt von Mu". Zusammenfassend würde ich sagen, dass es genauer ist zu sagen, dass Raku A) "ernsthafte Verzerrung sogar des klassenstandardbasierten OO mit nur ein paar Codezeilen" und B) "prototypbasiertes OO" unterstützt.
Raiph
Unter raku-musings.com/reblessed.html finden Sie meine Ansicht zu wichtigen Änderungen.
Arne Sommer
5

Siehe jnthns Antwort für eine maßgebliche Diskussion darüber, was genau passiert ist reblessund was dagegen zu tun ist.

es hat funktioniert ... Jetzt funktioniert es nicht ... Die Fehlermeldung macht keinen Sinn ... es soll mit geerbten Klassen funktionieren ... Zumindest war es ... Die Dokumentation ist nicht hilfreich

Diese (extrem lange!) Antwort ist möglicherweise eine Lektüre wert für diejenigen, die an einer weiteren Diskussion der Prinzipien und Praktiken des TDD- Ansatzes interessiert sind , der der Arbeit an der Programmiersprache Raku und verwandten Artefakten wie dem Rakudo-Compiler und den Inhalten von docs.raku.org zugrunde liegt .

Diese Antwort besteht aus spezifischen Antworten auf bestimmte Teile der ursprünglichen Frage von Arne und aus Kommentaren, die sie als Antwort auf eine frühere Version dieser Antwort verfasst haben. Meine Absicht war es, es für Arne nützlicher zu machen, während ich hoffentlich immer noch für andere nützlich bin.

Arne: Der in diesem Thread angegebene Code funktioniert nicht mehr: Wie kann ich ein Objekt in Raku reblessen?

Ich habe die akzeptierte Antwort auf diese SO aktualisiert, um auf diese SO zu verlinken.

Arne: Ich habe diesen Code letztes Jahr geschrieben und er hat dann funktioniert. Jetzt nicht

Die relevante Änderung wurde in einem Commit vom April 2019 erörtert , in dem jnthn schrieb:

Vor kurzem mussten Typen, die das Ziel einer reblessOperation waren, explizit als Mixin-Zieltypen erstellt werden, um die Optimierung zu unterstützen. ...

In einem Kommentar vor 11 Tagen zum Abschluss der Rakudo GH-Ausgabe "Rebless to a custom type scheint nicht mehr zu funktionieren" , schrieb er:

Sie müssen dafür sorgen, dass das is_mixingenannte Argument an ClassHOW.new_type... übergeben wird. Mit der Klassensyntax ist dies nicht möglich. Daher muss der Zieltyp des Rebless auch mithilfe der MOP zusammengestellt werden.

(Klicken Sie auf den obigen Link, um Hinweise zu erhalten, wie Sie das tun, was vorgeschlagen wird.)

Dieses Problem wird auch ein wenig weiter besprochen, da es funktioniert hat ... es hat plötzlich nicht mehr ... die Dokumentation ... sollte den Anrufabschnitt unten dokumentieren .

Arne: Es soll mit geerbten Klassen funktionieren. Zumindest war es das.

Braten - die r epository o f a ll s pec t ests - bestimmtwas Raku Code tun soll. (Die st von roa st kann gelesen werden als s upposed t o s.)

In einer anderen Nachricht vom April 2019 schrieb jnthn:

Es gab keine vorherige Spezifikation für Metamodel::Primitives.rebless. Ich habe dieses Spektakel hinzugefügt, damit es jetzt gibt. Dies bedeutet, dass es jetzt eine Definition dessen gibt, was voraussichtlich funktionieren wird.

Die Tatsache, dass Rakudos Verhalten von einer ausführbaren Testsuite spezifiziert wird, ist ein wesentlicher Bestandteil von @ Larrys Ansatz, um sicherzustellen, dass Raku sich zuverlässig verhält [1] und tiefgreifende Auswirkungen hat [2] .

Die Auswirkungen dieser Änderung auf ein weit verbreitetes Modul

Hier ist eine Momentaufnahme der Auswirkungen dieser Änderung auf das beliebte Inline :: Perl5-Modul.

Im April 2019 eröffnete niner eine Rakudo GH-Ausgabe über die Auswirkungen aufInline::Perl5 und ich habe unten einige Höhepunkte des Austauschs zwischen niner und jnthn extrahiert.

(Ich habe einige Dinge beseitigt, die im ursprünglichen Kontext wichtig waren, aber im Kontext dieses SO ablenkten. Bitte nehmen Sie nicht an, dass Sie das ursprüngliche Gespräch aus diesem Auszug vollständig verstanden haben . Wenn Sie Zweifel haben, klicken Sie auf den Link. )

niner: TBH, was ich hier mache, war wahrscheinlich immer ein bisschen faul ... Könnte sogar sein, dass ... ich [es] loswerden kann ... Wäre aber schön, wenn ich bereits bereitgestellte Inline :: Perl5-Versionen am Laufen halten würde .

jnthn: Es gab keine vorherige Spezifikation für Metamodel::Primitives.rebless. Ich habe [a] spectest hinzugefügt, so dass es jetzt gibt. Dies bedeutet, dass jetzt definiert ist, was voraussichtlich funktionieren wird und worauf sich Inline :: Perl5 verlassen kann.

Da unbekannte benannte Parameter ignoriert werden, aber :mixinin früheren Rakudo-Versionen nicht erforderlich waren, wäre es möglich, eine neue Inline :: Perl5-Version zu erstellen, die sowohl auf früheren Rakudo-Versionen als auch auf der kommenden Version funktioniert, also zumindest rückenkompatibel.

Ich glaube nicht, dass es eine Möglichkeit gibt, die Dinge für bestehende Inline :: Perl5-Versionen am Laufen zu halten ...

niner: Leider :mixinhilft das Übergeben in diesem Fall nicht, da das Rebless für eine Unterklasse der über erstellt wird Metamodel::Primitives.create_type. Die Unterklasse verwendet das Normale Perl6::ClassHOW.

Ich arbeite an einem großen Refactor, um den rebless Hack überhaupt loszuwerden. Ich öffne dieses Problem erneut, damit der Release-Manager weiß, dass Inline :: Perl5 für Rakudos Release-Kandidaten nicht funktioniert.

jnthn: Erstellen Sie diese Klasse mit der MOP? Sie können an weitergeben :is_mixin, Perl6::ClassHOW.new_typewenn ja.

niner: Nein, es ist für diese Situation:class Bar is Foo { }

Hilfe bei den Dokumenten

In einem Kommentar unter dieser Antwort haben Sie geschrieben:

Ich kann mit dem Dokumentationsteil helfen

Das klingt für mich nach einer sehr angemessenen und nützlichen Antwort auf das Problem im Herzen Ihrer SOQ. Ich hoffe, dass wir das Glück haben, dass dies eintritt.

wenn das hilft

Imo Ihr technisches Schreiben ist ausgezeichnet, also würde ich hoffen, dass das Endergebnis Ihrer Zusammenarbeit mit anderen, die an der Verbesserung beteiligt sind, eine wunderbare Sache wäre.

Grundlegende Einschränkungen für den Inhalt von docs.raku.org

Ein großer Teil des Grundes, warum ich den Rest dieser sehr ausführlichen Antwort auf eine so scheinbar einfache Frage geschrieben und sie nach dem anfänglichen Löschen wieder aufgenommen habe, nachdem Jonathan sie beantwortet hatte, war die Erörterung der Prinzipien und der Praxis des TDD- Ansatzes, an dem gearbeitet wird die Raku-Programmiersprache und verwandte Artefakte wie den Rakudo-Compiler und den Inhalt von docs.raku.org .

Aiui, die wünschenswerte Beziehung zwischen der Funktionsweise von Dingen in Raku und der tatsächlichen Funktionsweise in Rakudo und der Dokumentation von Dingen auf docs.raku.org läuft auf Folgendes hinaus :

  • Es muss davon ausgegangen werden, dass alles für immer der fundamentalen Natur eines Freiwilligenprojekts unterliegt. und innerhalb dieser Einschränkung:

  • Verhalten in Braten sollte nicht dokumentiert und anderes Verhalten soll es sein.

(Angesichts der verfügbaren Zeit, des Interesses und des Konsenses der Freiwilligen werden gelegentlich Ausnahmen für die Dokumentation des Verhaltens eines Rakudo mit ordnungsgemäßer Qualitätssicherung gemacht, das nicht durch Braten abgedeckt ist. In der gegenwärtigen Praxis scheint dies das Verhalten einer Rakudo-Version in einem veröffentlichten Rakudo-Stern zu bedeuten.)

Nutzlose Dokumentation

Die Dokumentation ist nicht hilfreich

Ich hielt das für einen fairen Kommentar. Alles in allem war die Dokumentation, wie sie war, als Sie Ihre Frage geschrieben haben, nicht hilfreich.

Die Dokumentation war nutzlos [im Jahr 2018]

Dies ist eine ganz andere Aussage.

Zu reblessdiesem Zeitpunkt gab es keinen Brateneintrag .

Wenn die docs.raku.org Seite auf rebless hatte sein Verhalten beschrieben , wie es im Jahr 2018 war, dann hätte das gewesen als nutzlos schlimmer , weil es falsch , dass das dann aktuelle Verhalten vorschlagen würde , unterstützt wurde. In Wirklichkeit gab es Spielraum dafür, eine zukünftige Version von Rakudo ohne vernünftige Aussicht einzubrechen. Das Verhalten von 2018 würde von den Kernentwicklern wieder hergestellt. Und tatsächlich geschah dies: Das nicht unterstützte Verhalten von 2018 brach zusammen und wurde nicht wieder hergestellt.

Angesichts des Konsenses darüber, was zu docs.raku.org gehört und was nicht (siehe oben), war das Hilfreichste, was seine reblessSeite tun konnte, entweder überhaupt nicht zu dokumentieren reblessoder, vielleicht besser, eine Seite dafür einzuschließen, aber Stellen Sie sicher, dass das Verhalten nicht beschrieben wurde. Wie war die Situation: Die Seite existierte; war nicht direkt hilfreich; und das war wohl besser als nichts.

(Es ist leicht vorstellbar, dass die Dinge noch besser sind. Was wäre zum Beispiel, wenn Seiten, die Funktionen dokumentieren, einen Prozentsatz enthalten, der den Status der mit dieser Funktion verbundenen Testabdeckung in der Version von Rakudo im neuesten Rakudo Star dokumentiert? Ein 0% könnte einen Leser sofort erkennen in dem Bewusstsein, dass diese Funktion nicht durch Braten abgedeckt wurde. Das heißt, obwohl diese Dokumentfunktion leicht vorstellbar ist , wer wird sie implementieren? Es ist ebenso leicht vorstellbar, dass es ein Kalenderjahr oder mehr fleißiger Arbeit dauern könnte und Zusammenarbeit, um sinnvoll zu implementieren und bereitzustellen, und dass die Leute denken, dass andere Dinge wichtiger sind.)

es hat funktioniert ... es hat plötzlich nicht mehr funktioniert ... die Dokumentation ... sollte den Anruf dokumentieren

es funktionierte

Es war "Glück", dass es funktioniert hat.

es funktionierte plötzlich nicht mehr

Weil Rakudo verbessert wurde.

Die Dokumentation ... sollte den Anruf dokumentieren

Wie bereits erläutert, der aktuelle Konsens der Gemeinschaft AIUI und / oder Arbeits Praxis ist: die Dokumentation sollten Sie dokumentieren eine bestimmte Version des Anrufs, nämlich dem Braten ‚d Verhalten für die Version von Rakudo in der neuesten Rakudo Stern; und KANN das Verhalten in anderen Versionen dokumentieren.

und nicht auf etwas anderes verweisen

Aiui, der derzeitige Konsens und / oder die Arbeitspraxis ist, dass das, was einige als "schwache" Dokumentbeiträge betrachten könnten, z. B. einige kurze, schnell geschriebene Inhalte und / oder Links außerhalb der Dokumente, eingeführt werden kann, wenn Freiwillige der Ansicht sind, dass eine sofortige Änderung gerechtfertigt ist, um zu reflektieren Einige Bedenken eines Benutzers (z. B. dieses SO) und dass es besser wäre, die "schwache" Änderung vorzunehmen, als überhaupt nichts zu tun. Sie können natürlich eine PR durchführen, um sie zu verbessern (oder um sie zurückzusetzen, wenn Sie wirklich das Gefühl haben, dass eine Änderung so "schwach" ist, dass die Sache noch schlimmer wird).

Der Verweis auf Änderungen in 2019.11 ist nach meiner Zählung 7 Monate frei

(Nach meiner Zählung ist es auch so, obwohl ich einen Compiler gesehen habe, der behauptet, 2019.03.1 mit der gleichen Verhaltensunterbrechung zu sein. [3] )

Ich denke, JJ hat die Änderung des Dokuments vorgenommen und jnthns Kommentar zur Anpassung an die Änderung falsch interpretiert. Ich denke derzeit, es ist besser als nichts, aber ich freue mich darauf, dass Sie es aktualisieren. :) :)

Fußnoten

[1] Einige Minuten nachdem Larry das Projekt, das zu Raku führte, in seiner Rede "State of the Onion" aus dem Jahr 2000 zum ersten Mal angekündigt hatte, wurde Folgendes gesagt :

Frage: Wird [Raku] Spezifikationen haben?

Larry: Was wir besonders hervorheben möchten ... ist vielleicht nicht so sehr die [Sprachdesign] -Spezifikation als vielmehr die Entwicklung unseres aktuellen Regressionstests ... zu einem Validierungstest dessen, was die Sprache tatsächlich bedeutet, und gehen Sie tatsächlich aus und erkunden Sie alle Ecken und crannies und sagen: "Dies ist [Raku], dies ist nicht [Raku]", und dann haben wir tatsächlich eine maschinenlesbare Spezifikation. Und für mich ist das tatsächlich viel wichtiger als das, was die Redewendung in der menschlich lesbaren Sache sagt.

[2] Natürlich funktioniert Braten für einen bestimmten Benutzer nur dann gut, wenn seine Tests die Bedürfnisse des Benutzers ausreichend abdecken. Arnes Problem zeigt, wie überraschend Lücken in der Abdeckung sein können. Eine Diskussion dieser Lücken im Jahr 2018 finden Sie unter Informationen zu Spezifikationen, Versionierung, Änderungen und… Bruch . Die gute Nachricht ist, dass Braten nur viele in Raku geschriebene Komponententests sind, um zu testen, ob Ausdrücke oder Konstrukte mit bestimmten Werten eine bestimmte Sache bewirken. Einzelpersonen oder Unternehmen können daher problemlos neue Tests zur Verbesserung der Testabdeckung beitragen. Und alles unter Versionskontrolle (git), sodass benutzerdefinierte Downstream-Tags, Zweige und Gabeln rentabel, nachhaltig und verwaltbar sind. ( In der Tat, das ist , wie neue Sprachversionen ( Christmas, Diwali, Eid(?), Etc.) verwaltet werden .)

[3] Ich habe einen Versuch gesehen, eine neue Klasse, die mit regulärer newclass is oldclassSyntax erstellt wurde, zu reblessieren, sowohl mit (auf meinem Laptop) als auch nicht (mit repl.it) mit Compilern, die behaupten zu sein 2019.03.1. (Vermutlich hat repl.it eine Version des Compiler-Quellcodes oder eine daraus kompilierte Binärdatei installiert, die kurz nach der Aktualisierung der Compiler-Version aus dem Master-Kopf entnommen wurde 2019.03.1, wobei die aktuelle Änderung vorgenommen wurde. Ich stelle fest, dass repl.it port ' Ich habe ihre Online-Raku-Antwort nicht veröffentlicht - ich habe sie zufällig entdeckt -, daher ist diese Situation nicht unangenehm, aber sie hat für mich die Notwendigkeit der $RAKU.compiler.verbose-configMethode verstärkt, die in den gerade verknüpften bearbeiteten / fehlerhaften Ausgaben verwendet wird.)

Raiph
quelle
Ich fand diesen Artikel, als ich versuchte herauszufinden, wie "rebless" funktioniert, da die Dokumentation nutzlos war: stackoverflow.com/questions/44486985/… Und dann funktionierte es. Und dann funktionierte es plötzlich nicht mehr und die Dokumentation war immer noch nutzlos. Es ist immer noch so, wie es den Anruf dokumentieren sollte, und nicht auf etwas anderes verweisen. Und der Hinweis auf Änderungen in 2019.11 ist nach meiner Zählung 7 Monate frei.
Arne Sommer
Ich kann mit dem Dokumentationsteil helfen, wenn das hilft.
Arne Sommer
@ArneSommer Bitte beachten Sie die neuen Abschnitte in meiner Antwort, beginnend mit Hilfe bei den Dokumenten .
Raiph