è questo l'intento del design di Raku?
È giusto dire che Raku non è del tutto impopolare in quest'area. La tua domanda tocca due temi nel design di Raku, che meritano entrambi una piccola discussione.
Raku ha valori l di prima classe
Raku fa un uso abbondante dei valori l come una cosa di prima classe. Quando scriviamo:
has $.x is rw;
Il metodo che viene generato è:
method x() is rw { $!x }
Il is rw
qui indica che il metodo restituisce un l-value - cioè, qualcosa che può essere assegnato. Quindi quando scriviamo:
$obj.x = 42;
Questo non è zucchero sintattico: è davvero una chiamata di metodo e quindi l'operatore di assegnazione viene applicato al risultato. Questo funziona, perché la chiamata del metodo restituisce il Scalar
contenitore dell'attributo, che può quindi essere assegnato. Si può usare l'associazione per dividerlo in due passaggi, per vedere che non è una banale trasformazione sintattica. Ad esempio, questo:
my $target := $obj.x;
$target = 42;
Assegnerebbe all'attributo oggetto. Questo stesso meccanismo è alla base di numerose altre funzionalità, inclusa l'assegnazione di elenchi. Ad esempio, questo:
($x, $y) = "foo", "bar";
Funziona costruendo un List
contenente i contenitori $x
e $y
, quindi, l'operatore di assegnazione in questo caso esegue l'iterazione di ciascun lato in modo da eseguire l'assegnazione. Questo significa che possiamo usare gli rw
accessor agli oggetti lì:
($obj.x, $obj.y) = "foo", "bar";
E tutto funziona in modo naturale. Questo è anche il meccanismo alla base dell'assegnazione a fette di array e hash.
Si può anche usare Proxy
per creare un contenitore di valore l in cui il comportamento della lettura e della scrittura è sotto il tuo controllo. Pertanto, potresti mettere in atto le azioni collaterali STORE
. Però...
Raku incoraggia i metodi semantici rispetto ai "setter"
Quando descriviamo OO, spesso emergono termini come "incapsulamento" e "nascondere i dati". L'idea chiave qui è che il modello di stato all'interno dell'oggetto, ovvero il modo in cui sceglie di rappresentare i dati necessari per implementare i suoi comportamenti (i metodi), è libero di evolversi, ad esempio per gestire i nuovi requisiti. Più complesso è l'oggetto, più questo diventa liberatorio.
Tuttavia, getter e setter sono metodi che hanno una connessione implicita con lo stato. Mentre potremmo affermare che stiamo ottenendo il nascondimento dei dati perché stiamo chiamando un metodo, non accedendo direttamente allo stato, la mia esperienza è che finiamo rapidamente in un luogo in cui il codice esterno sta eseguendo sequenze di chiamate del setter per realizzare un'operazione - che è una forma della caratteristica invidia anti-pattern. E se stiamo facendo che , è abbastanza certo che finiremo con la logica di fuori dell'oggetto che fa un mix di operazioni di getter e setter per ottenere un'operazione. Davvero, queste operazioni avrebbero dovuto essere esposte come metodi con nomi che descrivono ciò che si sta realizzando. Questo diventa ancora più importante se ci troviamo in una situazione simultanea; un oggetto ben progettato è spesso abbastanza facile da proteggere al limite del metodo.
Detto questo, molti usi class
sono tipi di record / prodotti: esistono semplicemente per raggruppare un insieme di elementi di dati. Non è un caso che il .
sigillo non generi solo un accessorio, ma anche:
- Opta l'attributo come impostato dalla logica di inizializzazione dell'oggetto predefinita (ovvero, a
class Point { has $.x; has $.y; }
può essere istanziato come Point.new(x => 1, y => 2)
) e lo rende anche nel .raku
metodo di dumping.
- Opta l'attributo
.Capture
nell'oggetto predefinito , il che significa che possiamo usarlo nella destrutturazione (ad es sub translated(Point (:$x, :$y)) { ... }
.).
Quali sono le cose che vorresti se stessi scrivendo in uno stile più procedurale o funzionale e usando class
come mezzo per definire un tipo di record.
Il design Raku non è ottimizzato per fare cose intelligenti nei setter, perché è considerato una cosa scadente per cui ottimizzare. È oltre ciò che è necessario per un tipo di record; in alcune lingue potremmo sostenere di voler fare la validazione di ciò che viene assegnato, ma in Raku possiamo rivolgerci ai subset
tipi per quello. Allo stesso tempo, se stiamo davvero facendo una progettazione OO, allora vogliamo un'API di comportamenti significativi che nasconda il modello statale, piuttosto che pensare in termini di getter / setter, che tendono a portare a un fallimento nel colocare dati e comportamento, che è comunque molto importante fare OO.