Raku rebless não funciona mais com classes herdadas

9

O código fornecido neste thread não funciona mais: como posso abençoar um objeto no Perl 6?

Eu escrevi esse código no ano passado e funcionou então. Agora não:

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

A mensagem de erro não faz sentido, pois deve funcionar com classes herdadas. Pelo menos foi.

A documentação não é útil; https://docs.raku.org/routine/rebless

Arne Sommer
fonte
Pode ser um erro de regressão. Provavelmente é melhor denunciá-lo como um problema de Rakudo.
jjmerelo 21/01
Houve algumas mudanças em fevereiro passado: github.com/perl6/nqp/blob/…
jjmerelo
Também atualizei a documentação com uma nota de rodapé apontando para a resposta @jnthn docs.raku.org/type/Metamodel::Primitives . Obrigado, raiph
jjmerelo 21/01

Respostas:

11

deve trabalhar com classes herdadas

Nunca era para ser tão geral. Eu projetei essa API e a implementei em primeiro lugar, e ela só foi planejada como um detalhe de implementação de mixins.

Até muito recentemente, não fazia parte do conjunto de testes de especificação de idiomas - e quando se tornou parte dele, já possuía sua semântica atual e mais restritiva. As restrições são importantes por razões de desempenho: quando sabemos que um tipo não é o que pode ser o destino de uma operação de mixin, podemos compilar os acessos de atributo JIT nesse objeto de maneira muito mais simples (pagamos uma mudança extra condicional todos os atributos acessam antes da alteração e agora precisam pagá-lo apenas na combinação de tipos de destino).

É possível modificar o programa original para funcionar usando o MOP para construir a classe. De fato, o seguinte não é exatamente o programa original; Fiz um pequeno ajuste para mostrar como é possível fornecer métodos na subclasse como uma função anônima, para evitar muitos clichês do 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

Embora essa seja a correção mais semanticamente direta do programa original, há uma maneira mais curta: use o butoperador no Personobjeto type para produzir um tipo mixin e retorná-lo e, em seguida, apenas ajuste seu nome ao seu gosto:

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;

Qual é apenas uma linha extra do que o original de qualquer maneira.

Jonathan Worthington
fonte
constant Woman = Person but role …Não sabia que isso poderia ser feito. E, portanto, exceto pela BEGINlinha, Raku praticamente consegue fazer um paradigma prototípico no estilo JS também!
User0721090601 22/01
Está bem. Obrigado pela explicação. Espero que ele chegue à documentação, pois docs.raku.org/routine/rebless é bastante inútil ... Atualizarei «Beginning Raku» em breve.
Arne Sommer
@ user0721090601 O Raku suporta, citando S12: "programação OO baseada em classe e em protótipo" . No entanto, se você construir objetos usando a classpalavra - chave , então, citando S12 novamente: "por padrão, os objetos derivados do Musuporte a um modelo baseado em classe bastante padrão ... bless... chama ... rotinas BUILD ... semântica padrão BUILD são herdado de Mu". Em resumo, eu argumentaria que é mais preciso dizer que Raku suporta A) "deformando seriamente até o OO baseado em classes padrão, com apenas algumas linhas de código" e B) "OO baseado em protótipo".
raiph 28/01
Veja raku-musings.com/reblessed.html para ver minha opinião sobre as últimas alterações.
Arne Sommer
5

Veja a resposta de jnthn para uma discussão autorizada sobre exatamente o que aconteceu reblesse o que fazer a respeito.

funcionou ... Agora não funciona. A mensagem de erro não faz sentido ... deve funcionar com classes herdadas ... Pelo menos foi ... A documentação não é útil

Esta resposta (ultra longa!) Pode ser lida para aqueles interessados ​​em uma discussão mais aprofundada dos princípios e práticas da abordagem TDD subjacente ao trabalho na linguagem de programação Raku e artefatos relacionados, como o compilador Rakudo e o conteúdo do docs.raku.org .

Essa resposta está estruturada como respostas específicas a partes específicas da pergunta original de Arne e aos comentários que eles escreveram em resposta a uma versão anterior dessa resposta. Minha intenção era torná-lo mais útil para Arne, enquanto espero que ainda seja útil para outras pessoas.

Arne: O código fornecido neste tópico não funciona mais: como posso abençoar um objeto no Raku?

Atualizei a resposta aceita para esse SO para criar um link para este SO.

Arne: Eu escrevi esse código no ano passado e funcionou então. Agora não

A mudança relevante foi discutida em um commit de abril de 2019 no qual jnthn escreveu:

Recentemente, tipos que eram o destino de uma reblessoperação começaram a precisar ser criados explicitamente como tipos de destino de mixagem, para ajudar na otimização. ...

Em um comentário, há 11 dias, encerrando o rakudo GH issue "Rebless para um tipo personalizado não parece mais funcionar" , ele escreveu:

Você precisará providenciar para que o is_mixinargumento nomeado seja passado para ClassHOW.new_type... Não há como fazer isso com a sintaxe da classe; portanto, o tipo de destino do rebless deve ser montado usando o MOP também.

(Clique no link acima para obter notas sobre como fazer o que sugere).

Esse problema também é discutido um pouco mais no funcionamento ... de repente não ... a documentação ... deve documentar a seção de chamada abaixo.

Arne: é suposto trabalhar com classes herdadas. Pelo menos foi.

assado - o r epository o f um ll s pec t ests - determina o código de Raku é suposto fazer. (A r de roa r pode ser lido como s upposed t o s.)

Em outra mensagem de abril de 2019, a jnthn escreveu:

Não havia especificações anteriores para Metamodel::Primitives.rebless. Eu adicionei este espetáculo para que agora exista. Isso significa que agora existe uma definição do que pode funcionar.

O fato de o comportamento de Rakudo ser especificado por um conjunto de testes executáveis ​​é uma parte fundamental da abordagem de @ Larry para garantir que Raku se comporte de maneira confiável [1] e tenha implicações profundas [2] .

O impacto dessa mudança em um módulo amplamente usado

Aqui está uma amostra do impacto dessa mudança no popular módulo Inline :: Perl5.

Em abril de 2019, a niner abriu uma questão rakudo GH sobre o impactoInline::Perl5 e extraí alguns destaques da troca entre niner e jnthn abaixo.

(Eu elidei algumas coisas que eram importantes no contexto original, mas perturbadoras no contexto desta SO. Por favor, não suponha que você tenha um entendimento completo da conversa original deste extrato. Em caso de dúvida, clique no link. )

niner: TBH, o que eu faço aqui provavelmente sempre foi meio suspeito ... Pode até ser isso ... Eu posso me livrar dele [...] ... Seria bom manter as versões Inline :: Perl5 em funcionamento .

jnthn: Não havia especificações anteriores para Metamodel::Primitives.rebless. Eu adicionei [a] mais espetacular para que agora exista. Isso significa que agora existe uma definição do que pode funcionar e no qual o Inline :: Perl5 pode confiar.

Como os parâmetros nomeados desconhecidos são ignorados, mas :mixinnão eram necessários nas versões anteriores do Rakudo, seria possível fazer uma nova versão do Inline :: Perl5 que funcione nas versões anteriores do Rakudo e na próxima, portanto, pode haver pelo menos compatível com as costas.

Eu não acho que haja alguma maneira de manter as coisas funcionando para as versões existentes do Inline :: Perl5 ...

niner: Infelizmente, a passagem :mixinnão ajuda nesse caso, pois o rebless é feito em uma subclasse da criada via Metamodel::Primitives.create_type. A subclasse usa o normal Perl6::ClassHOW.

Estou trabalhando em um grande refator para se livrar do truque de rejeição em primeiro lugar. Estou reabrindo esse problema para que o gerente de lançamento esteja ciente de que não há Inline :: Perl5 funcionando no candidato a lançamento do rakudo.

jnthn: Você cria essa classe usando o MOP? Você pode passar :is_mixinpara Perl6::ClassHOW.new_typese sim.

niner: Não, é para esta situação:class Bar is Foo { }

Ajudando com os documentos

Em um comentário abaixo desta resposta, você escreveu:

Eu posso ajudar com a parte da documentação

Isso me parece uma resposta muito apropriada e útil para o problema no coração do seu SOQ. Espero que tenhamos sorte o suficiente para que isso aconteça.

se isso ajuda

Como sua escrita técnica é excelente, espero que o resultado final de você trabalhar com outras pessoas envolvidas na melhoria seja uma coisa maravilhosa.

Restrições fundamentais no conteúdo de docs.raku.org

Uma grande parte do motivo pelo qual escrevi o restante desta resposta muito extensa para uma pergunta aparentemente simples e a restabeleci depois de excluí-la depois que Jonathan a respondeu, foi discutir os princípios e a prática da abordagem de TDD subjacente ao trabalho em a linguagem de programação Raku e artefatos relacionados, como o compilador Rakudo e o conteúdo docs.raku.org .

Aiui, a relação desejável entre como as coisas devem funcionar em Raku e como elas realmente funcionam em Rakudo, e como as coisas devem ser documentadas em docs.raku.org se resume a:

  • Presume-se que tudo deve estar sempre sujeito à natureza fundamental de um projeto voluntário; e, dentro dessa restrição:

  • Comportamento no assado deve ser documentado e outro comportamento não deve.

(Dado o tempo, o interesse e o consenso de voluntários disponíveis, ocasionalmente são feitas exceções para documentar o comportamento de um Rakudo com controle de qualidade que não é coberto pelo assado. Na prática atual, isso parece significar o comportamento de uma versão do Rakudo em um Rakudo Star lançado.)

Documentação inútil

A documentação não é útil

Eu considerei isso um comentário justo. Considerando tudo, a documentação como estava quando você escreveu sua pergunta não foi útil.

a documentação foi inútil [em 2018]

Esta é uma afirmação muito diferente.

Não havia cobertura de entrada de assados reblessnaquele momento.

Se a página docs.raku.org na rebless tivesse descrito seu comportamento como era em 2018, isso seria pior do que inútil, porque sugeriria incorretamente que o comportamento atual era suportado. Na realidade, havia margem para que ele quebrasse em uma versão futura do Rakudo sem uma perspectiva razoável de que o comportamento de 2018 seria restabelecido pelos desenvolvedores principais. E, de fato, isso aconteceu: seu comportamento não suportado a partir de 2018 quebrou e não foi restabelecido.

Portanto, dado o consenso sobre o que pertence a docs.raku.org e o que não pertence (veja acima), a coisa mais útil que sua reblesspágina poderia fazer era não documentar reblessou, talvez melhor, incluir uma página, mas verifique se não descreveu seu comportamento. Qual era a situação: a página existia; não foi diretamente útil; e isso era sem dúvida melhor que nada.

(É fácil imaginar que as coisas estão melhor ainda. Por exemplo, e se as páginas que documentam funções incluírem uma porcentagem que documenta o estado da cobertura do teste associado a essa função na versão do Rakudo na última estrela do Rakudo? Um 0% poderia imediatamente induzir o leitor sabendo que essa função não foi coberta pelo assado, embora seja fácil imaginar esse recurso de documento , quem o implementará? É igualmente fácil imaginar que poderia levar um ano civil ou mais de trabalho diligente e colaboração para implementar e implantar de maneira útil, e que as pessoas pensam que outras coisas são mais importantes.)

funcionou ... de repente não ... a documentação ... deve documentar a chamada

funcionou

Foi "sorte" que funcionou.

de repente não funcionou mais

Porque Rakudo foi melhorado.

a documentação ... deve documentar a chamada

Como explicado anteriormente, aiui o atual consenso da comunidade e / ou prática de trabalho é: a documentação DEVE documentar uma versão específica da chamada, ou seja, o comportamento do assado para a versão do Rakudo no Rakudo Star mais recente; e PODE documentar o comportamento em outras versões.

e não se referir a outra coisa

Aiui, o consenso atual e / ou prática de trabalho é que o que alguns consideram contribuições "fracas" de documentos, por exemplo, conteúdo breve e escrito apressadamente e / ou links fora dos documentos, PODE ser apresentado se os voluntários acharem que uma mudança imediata é necessária para refletir alguma preocupação levantada por um usuário (por exemplo, este SO) e que fazer a mudança "fraca" seria melhor do que não fazer nada. É claro que você pode fazer um PR para melhorá-lo (ou revertê-lo, se realmente sentir que uma mudança é tão "fraca" que piora as coisas).

a referência a alterações em 2019.11 é de 7 meses de folga pela minha contagem

(É algo assim pela minha contagem também, embora eu tenha visto um compilador alegando ser 2019.03.1 com a mesma quebra de comportamento. [3] )

Acho que JJ fez a alteração do documento e ele apenas interpretou mal o comentário de jnthn sobre como se adaptar à mudança. Atualmente, acho que é melhor do que nada, mas esperamos que você atualize-o. :)

Notas de rodapé

[1] O seguinte foi dito alguns minutos depois que Larry anunciou o projeto que levou a Raku em seu discurso de 2000 "Estado da Cebola" :

Pergunta: O [Raku] terá especificações?

Larry: o que particularmente queremos enfatizar ... talvez não seja tanto a especificação do [design da linguagem] quanto o desenvolvimento do nosso atual teste de regressão ... em um teste de validação do que a linguagem realmente significa e realmente saia e explore todos os cantos e recantos e diga: "Este é [Raku], este não é [Raku]" e, na verdade, temos uma especificação legível por máquina. E para mim isso é realmente muito mais importante do que diz o palavreado no legível humano.

[2] Obviamente, o assado só funciona bem para um determinado usuário se seus testes cobrirem suficientemente as necessidades do usuário. O problema de Arne demonstra como os buracos na cobertura podem ser surpreendentes. Para uma discussão sobre esses buracos em 2018, consulte Especificações, controle de versão, alterações e ... Quebra . A boa notícia é que o assado é apenas muitos testes de unidade escritos em Raku para testar se expressões ou construções com valores específicos fazem uma coisa específica. Portanto, é fácil para indivíduos ou empresas contribuir com novos testes para melhorar a cobertura dos testes. E tudo está sob controle de versão (git), para que tags, ramificações e garfos personalizados a jusante sejam viáveis, sustentáveis ​​e gerenciáveis. (Na verdade, é assim que novas versões linguísticas ( Christmas, Diwali, Eid(?), Etc.) são geridos.)

[3] Vi uma tentativa de abençoar uma nova classe criada usando newclass is oldclasssintaxe regular, tanto o trabalho (no meu laptop) quanto o não (no repl.it) usando os compiladores que afirmam ser 2019.03.1. (Presumivelmente, o repl.it instalou uma versão do código-fonte do compilador, ou um binário compilado a partir dele, retirado do cabeçalho principal logo após a atualização da versão do compilador 2019.03.1, com as alterações mais recentes. Não publiquei o seu raku repl online - descobri-o por acidente -, então não há nada desfavorável nessa situação, mas reforçou para mim a necessidade do $RAKU.compiler.verbose-configmétodo usado nas saídas quebradas / trabalhadas que acabei de vincular.)

raiph
fonte
Encontrei este artigo quando tentei descobrir como funciona "rebless", pois a documentação era inútil: stackoverflow.com/questions/44486985/… E funcionou, então. E, de repente, não funcionou mais, e a documentação ainda era inútil. Ainda é, pois deve documentar a chamada, e não se refere a outra coisa. E a referência a alterações em 2019.11 é de 7 meses de folga pela minha contagem.
Arne Sommer
Eu posso ajudar com a parte da documentação, se isso ajudar.
Arne Sommer
@ArneSommer Consulte as novas seções na minha resposta, começando com Ajudando com os documentos .
raiph 03/02