est-ce l'intention du design de Raku?
Il est juste de dire que Raku n'est pas entièrement dépourvu d'opinion dans ce domaine. Votre question touche à deux thèmes de la conception de Raku, qui méritent tous deux une petite discussion.
Raku a des valeurs l de première classe
Raku utilise abondamment les valeurs L étant une chose de première classe. Quand on écrit:
has $.x is rw;
La méthode générée est:
method x() is rw { $!x }
L' is rw
ici indique que la méthode renvoie une valeur l , c'est-à-dire quelque chose qui peut être assigné. Ainsi, lorsque nous écrivons:
$obj.x = 42;
Ce n'est pas du sucre syntaxique: c'est vraiment un appel de méthode, puis l'opérateur d'affectation appliqué au résultat. Cela fonctionne, car l'appel de méthode renvoie le Scalar
conteneur de l'attribut, qui peut ensuite être affecté à. On peut utiliser la liaison pour diviser cela en deux étapes, pour voir que ce n'est pas une transformation syntaxique triviale. Par exemple, ceci:
my $target := $obj.x;
$target = 42;
Serait l'attribution à l'attribut d'objet. Ce même mécanisme est à l'origine de nombreuses autres fonctionnalités, notamment l'attribution de liste. Par exemple, ceci:
($x, $y) = "foo", "bar";
Fonctionne en construisant un List
contenant les conteneurs $x
et $y
, puis l'opérateur d'affectation dans ce cas itère chaque côté par paire pour effectuer l'affectation. Cela signifie que nous pouvons y utiliser des rw
accesseurs d'objets:
($obj.x, $obj.y) = "foo", "bar";
Et tout cela fonctionne naturellement. C'est également le mécanisme derrière l'attribution aux tranches de tableaux et de hachages.
On peut également l'utiliser Proxy
pour créer un conteneur de valeur l où le comportement de lecture et d'écriture est sous votre contrôle. Ainsi, vous pourriez mettre les actions secondaires enSTORE
. Toutefois...
Raku encourage les méthodes sémantiques sur les "colons"
Lorsque nous décrivons OO, des termes comme «encapsulation» et «masquage de données» reviennent souvent. L'idée clé ici est que le modèle d'état à l'intérieur de l'objet - c'est-à-dire la façon dont il choisit de représenter les données dont il a besoin pour implémenter ses comportements (les méthodes) - est libre d'évoluer, par exemple pour gérer de nouvelles exigences. Plus l'objet est complexe, plus cela devient libérateur.
Cependant, les getters et setters sont des méthodes qui ont une connexion implicite avec l'État. Bien que nous puissions prétendre que nous réalisons la dissimulation des données parce que nous appelons une méthode, sans accéder directement à l'état, mon expérience est que nous nous retrouvons rapidement à un endroit où le code extérieur effectue des séquences d'appels de setter pour effectuer une opération - ce qui est une forme de la fonctionnalité envie anti-modèle. Et si nous faisons cela , il est assez certain que nous allons finir avec la logique en dehors de l'objet qui fait un mélange d'opérations getter et setter pour réaliser une opération. Vraiment, ces opérations auraient dû être exposées comme des méthodes avec un nom qui décrit ce qui est réalisé. Cela devient encore plus important si nous sommes dans un environnement simultané; un objet bien conçu est souvent assez facile à protéger à la frontière de la méthode.
Cela dit, de nombreuses utilisations de class
sont vraiment des types d'enregistrement / produit: elles existent pour simplement regrouper un ensemble d'éléments de données. Ce n'est pas un hasard si le .
sceau ne génère pas seulement un accesseur, mais aussi:
- Fait en sorte que l'attribut soit défini par la logique d'initialisation d'objet par défaut (c'est-à-dire que a
class Point { has $.x; has $.y; }
peut être instancié comme Point.new(x => 1, y => 2)
), et le rend également dans le.raku
méthode de vidage.
- Place l'attribut dans l'
.Capture
objet par défaut , ce qui signifie que nous pouvons l'utiliser dans la déstructuration (par exemple sub translated(Point (:$x, :$y)) { ... }
).
Quelles sont les choses que vous souhaiteriez si vous écriviez dans un style plus procédural ou fonctionnel et utilisiez class
comme moyen de définir un type d'enregistrement.
La conception Raku n'est pas optimisée pour faire des choses intelligentes dans les setters, car cela est considéré comme une mauvaise chose à optimiser. C'est au-delà de ce qui est nécessaire pour un type d'enregistrement; dans certaines langues, nous pourrions dire que nous voulons valider ce qui est attribué, mais dans Raku, nous pouvons nous tourner vers des subset
types pour cela. En même temps, si nous faisons vraiment une conception OO, nous voulons une API de comportements significatifs qui cache le modèle d'état, plutôt que de penser en termes de getters / setters, ce qui a tendance à conduire à un échec de colocalisation les données et le comportement, ce qui est de toute façon la raison de faire de l'OO.