Raku Rebless ne fonctionne plus avec les classes héritées

9

Le code donné dans ce fil ne fonctionne plus: comment puis-je ré-bénir un objet en Perl 6?

J'ai écrit ce morceau de code l'année dernière, et cela a fonctionné ensuite. Maintenant, ce n'est pas le cas:

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

Le message d'erreur n'a pas de sens, car il est censé fonctionner avec des classes héritées. C'était du moins le cas.

La documentation n'est pas utile; https://docs.raku.org/routine/rebless

Arne Sommer
la source
Cela pourrait être un bug de régression. Il vaut probablement mieux le signaler comme un problème Rakudo.
jjmerelo
Il y a eu quelques changements en février dernier: github.com/perl6/nqp/blob/…
jjmerelo
En outre, j'ai mis à jour la documentation avec une note de bas de page pointant vers @jnthn réponse docs.raku.org/type/Metamodel::Primitives . Merci, raiph
jjmerelo

Réponses:

11

il est censé fonctionner avec des classes héritées

Ce n'était jamais censé être ce général. J'ai conçu cette API et l'ai implémentée en premier lieu, et elle n'a jamais été conçue que comme un détail d'implémentation de mixins.

Jusqu'à très récemment, il ne faisait pas partie de la suite de tests de spécification de langage - et quand il en faisait partie, il avait déjà sa sémantique actuelle, plus restrictive. Les contraintes sont importantes pour des raisons de performances: lorsque nous savons qu'un type n'est pas celui qui peut être la cible d'une opération de mixage, nous pouvons compiler les accès aux attributs JIT sur cet objet en quelque chose de beaucoup plus simple (nous avons payé un déplacement conditionnel supplémentaire sur chaque accès d'attribut avant le changement, et maintenant il suffit de le payer sur les types cibles mixin).

Il est possible de modifier le programme d'origine pour qu'il fonctionne en utilisant le MOP pour construire la classe. En fait, ce qui suit n'est pas tout à fait le programme d'origine; J'ai fait un petit ajustement dans le but de montrer comment on peut fournir des méthodes dans la sous-classe en tant que rôle anonyme, afin d'éviter trop de passe-partout 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

Bien que ce soit la correction la plus sémantique directe du programme d'origine, il existe un moyen plus court: utilisez l' butopérateur sur l' Personobjet type pour produire un type mixin et le renvoyer, puis ajustez simplement son nom à votre convenance:

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;

Ce qui n'est de toute façon qu'une ligne de plus que l'original.

Jonathan Worthington
la source
constant Woman = Person but role …Je ne savais pas que cela pouvait être fait. Et donc, sauf pour la BEGINligne, Raku réussit à peu près à pouvoir faire un paradigme prototypique de style JS!
user0721090601
D'accord. Merci pour l'explication. J'espère qu'il trouvera son chemin dans la documentation, car docs.raku.org/routine/rebless est assez inutile ... Je mettrai à jour «Beginning Raku» sous peu.
Arne Sommer
@ user0721090601 Raku prend en charge, citant S12: "programmation OO basée sur les classes et sur les prototypes" . Cependant, si vous construisez des objets en utilisant le classmot - clé , alors, en citant à nouveau S12: "par défaut, les objets dérivés de Muprennent en charge un modèle basé sur une classe assez standard ... bless... appelle ... les routines BUILD ... la sémantique BUILD par défaut est hérité de Mu". En résumé, je dirais qu'il est plus exact de dire que Raku prend en charge A) "déformant sérieusement même le OO standard basé sur la classe des tourbières avec seulement quelques lignes de code" et B) "OO basé sur un prototype".
raiph
Voir raku-musings.com/reblessed.html pour mon avis sur les changements de rupture.
Arne Sommer
5

Voir la réponse de jnthn pour une discussion faisant autorité sur précisément ce qui s'est passé reblesset ce qu'il faut faire à ce sujet.

ça a fonctionné ... Maintenant ça ne marche pas ... Le message d'erreur n'a pas de sens ... il est censé fonctionner avec les classes héritées ... Au moins c'était ... La documentation n'est pas utile

Cette réponse (ultra longue!) Peut être lue pour ceux qui souhaitent approfondir les principes et la pratique de l' approche TDD qui sous-tend les travaux sur le langage de programmation Raku et les artefacts connexes tels que le compilateur Rakudo et le contenu docs.raku.org .

Cette réponse est structurée comme des réponses spécifiques à des parties particulières de la question originale d'Arne et des commentaires qu'ils ont écrits en réponse à une version antérieure de cette réponse. Mon intention était de le rendre plus utile à Arne tout en étant, espérons-le, toujours utile aux autres.

Arne: Le code donné dans ce fil ne fonctionne plus: comment puis-je ré-bénir un objet dans Raku?

J'ai mis à jour la réponse acceptée à cet OS pour créer un lien vers cet OS.

Arne: J'ai écrit ce morceau de code l'année dernière, et cela a fonctionné ensuite. Maintenant ça ne marche pas

Le changement pertinent a été discuté dans un engagement d'avril 2019 dans lequel jnthn a écrit:

Récemment, les types qui étaient la cible d'une reblessopération ont commencé à être créés explicitement en tant que types cibles mixtes, pour faciliter l'optimisation. ...

Dans un commentaire il y a 11 jours clôturant le numéro de rakudo GH "Rebless à un type personnalisé ne semble plus fonctionner" , il a écrit:

Vous devrez vous arranger pour que l' is_mixinargument nommé soit passé à ClassHOW.new_type... Il n'y a aucun moyen de le faire avec la syntaxe de classe, donc le type cible de la relbless devra également être assemblé en utilisant le MOP.

(Cliquez sur le lien ci-dessus pour des notes sur la façon de faire ce qu'il suggère.)

Ce problème est également abordé un peu plus loin dans le document qui a fonctionné ... il ne l'a pas soudainement ... la documentation ... devrait documenter la section d' appel ci-dessous.

Arne: il est censé fonctionner avec des classes héritées. C'était du moins le cas.

rôti - la r epository o f un ll s pec t ests - détermine quel code Raku est censé faire. (La st de roa st peut être lu comme s upposed t o s.)

Dans un autre message d'avril 2019, jnthn a écrit:

Il n'y avait aucune spécification précédente pour Metamodel::Primitives.rebless. J'ai ajouté ce spectre pour que maintenant il y en ait. Cela signifie qu'il existe maintenant une définition de ce qui peut fonctionner.

Le fait que le comportement de Rakudo soit spécifié par une suite de tests exécutables est un élément fondamental de l'approche de @ Larry pour garantir que Raku se comporte de manière fiable [1] et a de profondes implications [2] .

L'impact de ce changement sur un module largement utilisé

Voici un aperçu de l'impact de ce changement qui se déroule pour le module populaire Inline :: Perl5.

En avril 2019, niner a ouvert un numéro de rakudo GH sur l'impact surInline::Perl5 et j'ai extrait ci-dessous quelques faits saillants de l'échange entre niner et jnthn.

(J'ai élidé certaines choses qui étaient importantes dans le contexte d'origine, mais distrayantes dans le contexte de cet OS. Veuillez ne pas supposer que vous avez une compréhension complète de la conversation originale de cet extrait. En cas de doute, cliquez sur le lien. )

niner: TBH ce que je fais ici a probablement toujours été un peu louche ... Cela pourrait même être ça ... Je peux m'en débarrasser ... Ce serait bien de garder les versions Inline :: Perl5 déjà déployées et opérationnelles .

jnthn: Il n'y avait aucune spécification précédente pour Metamodel::Primitives.rebless. J'ai ajouté [un] spectre pour que maintenant il y en ait. Cela signifie qu'il existe maintenant une définition de ce qui peut fonctionner et sur lequel Inline :: Perl5 peut s'appuyer.

Étant donné que les paramètres nommés inconnus sont ignorés, mais :mixinn'étaient pas requis sur les versions précédentes de Rakudo, il serait alors possible de créer une nouvelle version d'Inline :: Perl5 qui peut fonctionner sur les versions précédentes de Rakudo ainsi que sur la prochaine, donc il peut au moins y avoir back-compat.

Je ne pense pas qu'il y ait moyen de faire fonctionner les versions existantes d'Inline :: Perl5 ...

niner: Malheureusement, le dépassement :mixinn'aide pas dans ce cas car le rebless se fait sur une sous-classe de celle créée via Metamodel::Primitives.create_type. La sous-classe utilise la normale Perl6::ClassHOW.

Je travaille sur un remaniement majeur pour se débarrasser du hack sans rebond en premier lieu. Je rouvre ce problème afin que le responsable de la version sache qu'il n'y a pas de Inline :: Perl5 sur le candidat à la sortie de rakudo.

jnthn: Créez-vous cette classe à l'aide du MOP? Vous pouvez passer :is_mixinà Perl6::ClassHOW.new_typesi oui.

niner: Non, c'est pour cette situation:class Bar is Foo { }

Aider avec les documents

Dans un commentaire ci-dessous, vous avez écrit cette réponse:

Je peux aider avec la partie documentation

Cela me semble être une réponse très appropriée et utile au problème au cœur de votre SOQ. J'espère que nous avons la chance que cela se réalise.

si cela aide

Imo votre rédaction technique est excellente, donc j'espère que le résultat final de votre collaboration avec d'autres personnes impliquées dans l'amélioration sera une chose merveilleuse.

Contraintes fondamentales sur le contenu de docs.raku.org

Une grande partie de la raison pour laquelle j'ai écrit le reste de cette réponse très complète à une question aussi simple en apparence et que j'ai rétablie après l'avoir supprimée une fois que Jonathan y avait répondu, était de discuter des principes et de la pratique de la approche TDD sur laquelle reposent les travaux. le langage de programmation Raku et les artefacts associés tels que le compilateur Rakudo et le contenu docs.raku.org .

Aiui, la relation souhaitable entre comment les choses sont censées fonctionner à Raku, et comment elles fonctionnent réellement à Rakudo, et comment les choses sont censées être documentées sur docs.raku.org se résume à:

  • Tout DOIT être présumé être à jamais soumis à la nature fondamentale d'un projet de bénévolat; et, dans le cadre de cette contrainte:

  • Le comportement du rôti DEVRAIT être documenté et aucun autre comportement NE DEVRAIT PAS.

(Compte tenu du temps, de l'intérêt et du consensus des bénévoles disponibles, des exceptions sont parfois faites pour documenter le comportement d'un Rakudo correctement certifié qui n'est pas couvert par le rôti. Dans la pratique actuelle, cela semble signifier le comportement d'une version Rakudo dans une Rakudo Star publiée.)

Documentation inutile

La documentation n'est pas utile

J'ai considéré cela comme un commentaire juste. Tout bien considéré, la documentation telle qu'elle était lorsque vous avez rédigé votre question n'était pas utile.

la documentation était inutile [en 2018]

Ceci est une déclaration très différente.

Il n'y avait aucune entrée de rôti couvrant rebless à ce moment-là.

Si la page docs.raku.org sur rebless avait décrit son comportement tel qu'il était en 2018, cela aurait été pire qu'inutile car cela suggérerait à tort que le comportement alors en vigueur était pris en charge. En réalité, il était possible qu'il s'introduise dans une future version de Rakudo sans perspective raisonnable, le comportement de 2018 serait rétabli par les principaux développeurs. Et en effet, cela s'est produit: son comportement non pris en charge à partir de 2018 s'est rompu et n'a pas été réintégré.

Donc, étant donné le consensus sur ce qui appartient à docs.raku.org et ce qui ne le fait pas (voir ci-dessus), la chose la plus utile que sa reblesspage pourrait faire était de ne pas documenter reblessdu tout ou, peut-être mieux, d'inclure une page pour cela, mais assurez-vous qu'il n'a pas décrit son comportement. Quelle était la situation: la page existait; n'était pas directement utile; et c'était sans doute mieux que rien.

(Il est facile d'imaginer que les choses s'améliorent encore. Par exemple, que se passerait-il si les pages documentant les fonctions incluaient un pourcentage documentant l'état de la couverture de test associée à cette fonction dans la version de Rakudo dans la dernière Rakudo Star? Un 0% pourrait immédiatement indiquer un lecteur à une prise de conscience que cette fonction n'était pas couverte par le rôti. Cela dit, bien que cette fonctionnalité de doc soit facile à imaginer , qui va l'implémenter? Il est tout aussi facile d'imaginer que cela pourrait prendre une année civile ou plus de travail assidu et la collaboration pour mettre en œuvre et déployer utilement, et que les gens pensent que d'autres choses sont plus importantes.)

ça a fonctionné ... ça n'a tout à coup pas fonctionné ... la documentation ... devrait documenter l'appel

ça a marché

C'était de la «chance», ça a marché.

ça n'a plus marché du coup

Parce que Rakudo a été amélioré.

la documentation ... devrait documenter l'appel

Comme expliqué précédemment, le consensus et / ou les pratiques de travail actuels de la communauté sont les suivants: la documentation DEVRAIT documenter une version particulière de l'appel, à savoir le comportement de torréfaction de la version de Rakudo dans la dernière Rakudo Star; et PEUT documenter le comportement dans d'autres versions.

et ne pas se référer à autre chose

Aiui, le consensus actuel et / ou la pratique de travail est que ce que certains pourraient considérer comme des contributions doc "faibles", par exemple un contenu bref et rédigé à la hâte et / ou des liens en dehors des documents, PEUT être introduit si les volontaires sentent qu'un changement immédiat est justifié pour refléter une certaine inquiétude soulevée par un utilisateur (par exemple, cet OS) et qu'il serait préférable de faire le changement "faible" plutôt que de ne rien faire du tout. Vous pouvez bien sûr faire un RP pour l'améliorer (ou le revenir en arrière si vous sentez vraiment qu'un changement est si "faible" qu'il aggrave les choses).

la référence aux changements en 2019.11 est de 7 mois de congé selon mon décompte

(C'est quelque chose comme ça d'après mon décompte aussi, bien que j'ai vu un compilateur prétendant être 2019.03.1 avec la même rupture de comportement. [3] )

Je pense que JJ a fait le changement de doc et il a juste mal interprété le commentaire de jnthn sur la façon de s'adapter au changement. Je pense actuellement que c'est mieux que rien, mais je suis impatient de le mettre à jour. :)

Notes de bas de page

[1] Ce qui suit a été dit quelques minutes après que Larry avait annoncé pour la première fois le projet qui avait mené à Raku dans son discours de 2000 sur "L'état de l'oignon" :

Question: [Raku] aura-t-il des spécifications?

Larry: ce que nous voulons particulièrement souligner ... ce n'est peut-être pas tant la spécification [de conception du langage] que le développement de notre test de régression actuel ... en un test de validation de ce que le langage signifie réellement et réellement aller explorer tous les coins et des recoins et disent: «C'est [Raku], ce n'est pas [Raku]», puis nous avons en fait une spécification lisible par machine. Et pour moi, c'est en réalité beaucoup plus important que ce que dit le verbiage dans la chose lisible par l'homme.

[2] Bien sûr, le rôti ne fonctionne bien pour un utilisateur donné que si ses tests couvrent suffisamment les besoins de l'utilisateur. Le problème d'Arne montre à quel point les trous dans la couverture peuvent être surprenants. Pour une discussion de ces trous tels qu'ils se présentaient en 2018, voir À propos des spécifications, du contrôle de version, des modifications et… des bris . La bonne nouvelle est que le rôti n'est que de nombreux tests unitaires écrits en Raku pour tester que les expressions ou les constructions avec des valeurs particulières font une chose particulière. Il est donc facile pour les particuliers ou les entreprises de contribuer à de nouveaux tests pour améliorer la couverture des tests. Et tout est sous contrôle de version (git), donc les balises, les branches et les fourches personnalisées en aval sont viables, durables et gérables. ( En effet, c'est comment les nouvelles versions linguistiques ( Christmas, Diwali, Eid(?), Etc.) sont gérées.)

[3] J'ai vu une tentative de ré-bénédiction d'une nouvelle classe créée en utilisant la newclass is oldclasssyntaxe régulière à la fois travailler (sur mon ordinateur portable) et ne pas fonctionner (sur repl.it) en utilisant des compilateurs qui prétendent l'être 2019.03.1. (On peut supposer que repl.it a installé une version du code source du compilateur, ou un binaire compilé à partir de celui-ci, extrait de la tête principale peu de temps après la mise à jour de la version du compilateur 2019.03.1, avec le changement de rupture en place. Je note que repl.it n'a pas '' Je n'ai pas rendu public leur raku en ligne - je l'ai découvert par accident - il n'y a donc rien de fâcheux dans cette situation mais cela a renforcé pour moi la nécessité de la $RAKU.compiler.verbose-configméthode utilisée dans les sorties travaillées / cassées que je viens de relier.)

raiph
la source
J'ai trouvé cet article lorsque j'ai essayé de comprendre comment fonctionnait la «rebless», car la documentation était inutile: stackoverflow.com/questions/44486985/… Et cela a fonctionné, alors. Et puis soudain, cela n'a plus fonctionné, et la documentation était toujours inutile. Il l'est toujours, car il devrait documenter l'appel et ne pas se référer à autre chose. Et la référence aux changements dans 2019.11 est de 7 mois de congé selon mon décompte.
Arne Sommer
Je peux vous aider avec la partie documentation, si cela vous aide.
Arne Sommer
@ArneSommer Veuillez voir les nouvelles sections dans ma réponse en commençant par Aider avec les documents .
raiph