#Private attribute example
class C {
has $!w; #private attribute
multi method w { $!w } #getter method
multi method w ( $_ ) { #setter method
warn “Don’t go changing my w!”; #some side action
$!w = $_
}
}
my $c = C.new
$c.w( 42 )
say $c.w #prints 42
$c.w: 43
say $c.w #prints 43
#but not
$c.w = 44
Cannot modify an immutable Int (43)
até agora, tão razoável, e então
#Public attribute example
class C {
has $.v is rw #public attribute with automatic accessors
}
my $c = C.new
$c.v = 42
say $c.v #prints 42
#but not
$c.v( 43 ) #or $c.v: 43
Too many positionals passed; expected 1 argument but got 2
Gosto da iminência da atribuição '=', mas preciso da facilidade de participar de ações paralelas que os vários métodos fornecem. Entendo que esses são dois mundos diferentes e que eles não se misturam.
MAS - Eu não entendo por que não posso simplesmente ir $ cv (43) Para definir um atributo público
- Eu sinto que o raku está me guiando para não misturar esses dois modos - alguns atributos privados e outros públicos e que a pressão é direcionada ao método (com alguns: açúcar do cólon) - é essa a intenção do design de Raku?
- Estou esquecendo de algo?
is rw
é especificado. O retorno de um proxy não altera o número de parâmetros permitidos no acessador.= foo
e.(foo)
para definir) e permitindo que os efeitos colaterais sejam feitos nos dois casos (mas não quando buscados apenas): tio.run/…Respostas:
É justo dizer que Raku não é totalmente imparcial nessa área. Sua pergunta aborda dois temas no design de Raku, que merecem uma pequena discussão.
Raku tem valores l de primeira classe
Raku faz uso abundante dos valores l, sendo uma coisa de primeira classe. Quando escrevemos:
O método que é gerado é:
O
is rw
aqui indica que o método está retornando um valor l - ou seja, algo que pode ser atribuído. Assim, quando escrevemos:Isso não é açúcar sintático: é realmente uma chamada de método e, em seguida, o operador de atribuição sendo aplicado ao resultado dela. Isso funciona, porque a chamada do método retorna o
Scalar
contêiner do atributo, o qual pode ser atribuído. Pode-se usar a ligação para dividir isso em duas etapas, para ver que não é uma transformação sintática trivial. Por exemplo, isto:Estaria atribuindo ao atributo de objeto. Esse mesmo mecanismo está por trás de vários outros recursos, incluindo a atribuição de listas. Por exemplo, isto:
Trabalha construindo um
List
contendo os contêineres$x
e$y
, em seguida, o operador de atribuição, neste caso, itera cada lado em pares para realizar a atribuição. Isso significa que podemos usarrw
acessadores de objetos lá:E tudo funciona naturalmente. Esse também é o mecanismo por trás da atribuição a fatias de matrizes e hashes.
Também se pode usar
Proxy
para criar um contêiner de valor l onde o comportamento de ler e escrever está sob seu controle. Assim, você pode colocar as ações secundáriasSTORE
. Contudo...Raku incentiva métodos semânticos sobre "setters"
Quando descrevemos OO, termos como "encapsulamento" e "ocultação de dados" costumam aparecer. A idéia principal aqui é que o modelo de estado dentro do objeto - ou seja, a maneira como escolhe representar os dados necessários para implementar seus comportamentos (os métodos) - é livre para evoluir, por exemplo, para lidar com novos requisitos. Quanto mais complexo o objeto, mais libertador ele se torna.
No entanto, getters e setters são métodos que têm uma conexão implícita com o estado. Embora possamos afirmar que estamos conseguindo ocultar dados porque estamos chamando um método, e não acessando diretamente o estado, minha experiência é que terminamos rapidamente em um local onde o código externo está fazendo sequências de chamadas de setter para realizar uma operação - o que é uma forma do recurso inveja o antipadrão. E se fizermos isso , é certo que acabaremos com lógica fora do objeto que faz uma mistura de operações getter e setter para conseguir uma operação. Realmente, essas operações deveriam ter sido expostas como métodos com nomes que descrevem o que está sendo alcançado. Isso se torna ainda mais importante se estivermos em um cenário simultâneo; um objeto bem projetado geralmente é bastante fácil de proteger no limite do método.
Dito isto, muitos usos de
class
são realmente tipos de registro / produto: eles existem para simplesmente agrupar vários itens de dados. Não é por acaso que o.
sigilo não gera apenas um acessador, mas também:class Point { has $.x; has $.y; }
pode ser instanciada comoPoint.new(x => 1, y => 2)
) e também a processa no.raku
método de dumping..Capture
objeto padrão , o que significa que podemos usá-lo na desestruturação (por exemplosub translated(Point (:$x, :$y)) { ... }
).Quais são as coisas que você gostaria se estivesse escrevendo em um estilo mais processual ou funcional e usando
class
como um meio para definir um tipo de registro.O design do Raku não é otimizado para fazer coisas inteligentes nos levantadores, porque isso é considerado ruim para se otimizar. Está além do necessário para um tipo de registro; em alguns idiomas, poderíamos argumentar que queremos validar o que está sendo atribuído, mas em Raku podemos recorrer a
subset
tipos para isso. Ao mesmo tempo, se estamos realmente fazendo um projeto de OO, queremos uma API de comportamentos significativos que oculte o modelo de estado, em vez de pensar em termos de getters / setters, que tendem a levar a uma falha na colocação dados e comportamento, que é muito importante para fazer OO de qualquer maneira.fonte
Proxy
es (embora eu tenha sugerido isso ha). A única vez que os achei terrivelmente úteis é para mimLanguageTag
. Internamente, o$tag.region
retorna um objeto do tipoRegion
(como ele é armazenado internamente), mas a realidade é que é infinitamente mais conveniente para as pessoas para dizer$tag.region = "JP"
mais$tag.region.code = "JP"
. E isso é apenas temporário até que eu possa expressar uma coerção doStr
tipo, por exemplo,has Region(Str) $.region is rw
(que requer dois recursos separados, de baixa prioridade, planejados)Bem, isso depende do arquiteto. Mas, falando sério, não, essa simplesmente não é a maneira padrão como Raku trabalha.
Agora, seria perfeitamente possível criar um
Attribute
traço no espaço módulo, algo comois settable
, que iria criar um método de acesso alternativo que faria aceitar um valor único para definir o valor. O problema de fazer isso no núcleo é: acho que existem basicamente dois campos no mundo sobre o valor de retorno de um mutador: retornaria o novo valor ou o valor antigo ?Entre em contato comigo se você estiver interessado em implementar essa característica no espaço do módulo.
fonte
Atualmente, suspeito que você acabou de ficar confuso. 1 Antes de abordar isso, vamos começar com o que você não está confuso:
Você pode fazer todas essas coisas. Ou seja, você usa
=
atribuição e vários métodos e "apenas vai$c.v( 43 )
", tudo ao mesmo tempo, se você quiser:Uma possível fonte de confusão 1
Nos bastidores,
has $.foo is rw
gera um atributo e um único método ao longo das linhas de:O exposto acima não está certo. Dado o comportamento que estamos vendo, gerada automaticamente do compilador
foo
método é de alguma forma ser declarado de tal forma que qualquer novo método de mesmo nome em silêncio sombras de TI. 2Portanto, se você deseja um ou mais métodos personalizados com o mesmo nome que um atributo, deve replicar manualmente o método gerado automaticamente se desejar manter o comportamento pelo qual ele normalmente seria responsável.
Notas de rodapé
1 Veja a resposta da jnthn para obter uma contabilidade clara, completa e autorizada da opinião de Raku sobre getters / setters privados x públicos e o que ele faz nos bastidores quando você declara getters / setters públicos (por exemplo, gravação
has $.foo
).2 Se um método acessador gerado automaticamente para um atributo fosse declarado
only
, presumo que Raku lançaria uma exceção se um método com o mesmo nome fosse declarado. Se ele foi declaradomulti
, não deve ser ocultado se o novo método também foi declaradomulti
e, caso contrário, deve gerar uma exceção. Portanto, o acessador gerado automaticamente está sendo declarado com nemonly
nemmulti
mas de alguma forma que permita sombreamento silencioso.fonte