Essa é a intenção do design de Raku?
É 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:
has $.x is rw;
O método que é gerado é:
method x() is rw { $!x }
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:
$obj.x = 42;
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:
my $target := $obj.x;
$target = 42;
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:
($x, $y) = "foo", "bar";
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 usar rw
acessadores de objetos lá:
($obj.x, $obj.y) = "foo", "bar";
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árias STORE
. 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:
- Opta que o atributo seja definido pela lógica de inicialização do objeto padrão (ou seja, a
class Point { has $.x; has $.y; }
pode ser instanciada como Point.new(x => 1, y => 2)
) e também a processa no .raku
método de dumping.
- Opta o atributo no
.Capture
objeto padrão , o que significa que podemos usá-lo na desestruturação (por exemplo sub 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.