Désolé pour le titre maladroit - si je pouvais trouver un titre concis, je n'aurais pas à poser la question.
Supposons que j'ai un type de liste immuable. Il a une opération Foo(x)
qui retourne une nouvelle liste immuable avec l'argument spécifié comme élément supplémentaire à la fin. Donc, pour construire une liste de chaînes avec les valeurs "Bonjour", "immuable", "monde", vous pouvez écrire:
var empty = new ImmutableList<string>();
var list1 = empty.Foo("Hello");
var list2 = list1.Foo("immutable");
var list3 = list2.Foo("word");
(Il s'agit du code C #, et je suis plus intéressé par une suggestion C # si vous pensez que la langue est importante. Ce n'est pas fondamentalement une question de langue, mais les idiomes de la langue peuvent être importants.)
L'important est que les listes existantes ne soient pas modifiées par Foo
- donc empty.Count
retournerait toujours 0.
Une autre façon (plus idiomatique) d'arriver au résultat final serait:
var list = new ImmutableList<string>().Foo("Hello")
.Foo("immutable")
.Foo("word");
Ma question est: quel est le meilleur nom pour Foo?
EDIT 3 : Comme je le révèle plus tard, le nom du type pourrait ne pas être réellement ImmutableList<T>
, ce qui rend la position claire. Imaginez plutôt que c'est TestSuite
et qu'il est immuable car l'ensemble du cadre dont il fait partie est immuable ...
(Fin du montage 3)
Options que j'ai trouvées jusqu'à présent:
Add
: commun en .NET, mais implique une mutation de la liste d'origineCons
: Je crois que c'est le nom normal dans les langages fonctionnels, mais sans signification pour ceux qui n'ont pas d'expérience dans de tels langagesPlus
: mon préféré jusqu'à présent, cela n'implique pas de mutation pour moi . Apparemment, cela est également utilisé dans Haskell mais avec des attentes légèrement différentes (un programmeur Haskell pourrait s'attendre à ce qu'il ajoute deux listes ensemble plutôt que d'ajouter une seule valeur à l'autre liste).With
: cohérent avec d'autres conventions immuables, mais n'a pas tout à fait la même "addition" à l'OMI.And
: peu descriptif.- Surcharge de l'opérateur pour +: je n'aime vraiment pas beaucoup ça; Je pense généralement que les opérateurs ne devraient être appliqués qu'aux types de niveau inférieur. Mais je suis persuadé!
Les critères que j'utilise pour choisir sont:
- Donne l'impression correcte du résultat de l'appel de méthode (c'est-à-dire qu'il s'agit de la liste d'origine avec un élément supplémentaire)
- Indique aussi clairement que possible qu'il ne mute pas la liste existante
- Cela semble raisonnable lorsqu'il est enchaîné comme dans le deuxième exemple ci-dessus
Veuillez demander plus de détails si je ne me fais pas assez clair ...
EDIT 1: Voici mon raisonnement pour préférer Plus
à Add
. Considérez ces deux lignes de code:
list.Add(foo);
list.Plus(foo);
À mon avis (et c'est une chose personnelle), ce dernier est clairement buggé - c'est comme écrire "x + 5;" comme une déclaration à part entière. La première ligne semble correcte, jusqu'à ce que vous vous souveniez qu'elle est immuable. En fait, la façon dont l'opérateur plus seul ne mute pas ses opérandes est une autre raison pour laquelle Plus
je préfère. Sans la légère lourdeur de la surcharge des opérateurs, cela donne toujours les mêmes connotations, qui incluent (pour moi) de ne pas muter les opérandes (ou la méthode cible dans ce cas).
EDIT 2: Raisons de ne pas aimer Add.
Diverses réponses sont effectivement: "Allez avec Add. C'est ce qui DateTime
fait, et String
a des Replace
méthodes, etc. qui ne rendent pas l'immuabilité évidente." Je suis d'accord - il y a priorité ici. Cependant, j'ai vu beaucoup de gens appellent DateTime.Add
ou String.Replace
et attendent une mutation . Il y a des tas de questions de newsgroup (et probablement SO si je creuse) auxquelles répond "Vous ignorez la valeur de retour de String.Replace
; les chaînes sont immuables, une nouvelle chaîne est retournée."
Maintenant, je devrais révéler une subtilité à la question - le type peut ne pas être en fait une liste immuable, mais un type immuable différent. En particulier, je travaille sur un cadre d'analyse comparative où vous ajoutez des tests à une suite, et qui crée une nouvelle suite. Il pourrait être évident que:
var list = new ImmutableList<string>();
list.Add("foo");
ne va rien accomplir, mais cela devient beaucoup plus trouble lorsque vous le changez en:
var suite = new TestSuite<string, int>();
suite.Add(x => x.Length);
On dirait que ça devrait aller. Alors que cela, pour moi, rend l'erreur plus claire:
var suite = new TestSuite<string, int>();
suite.Plus(x => x.Length);
Cela ne demande qu'à être:
var suite = new TestSuite<string, int>().Plus(x => x.Length);
Idéalement, j'aimerais que mes utilisateurs n'aient pas à être informés que la suite de tests est immuable. Je veux qu'ils tombent dans le gouffre du succès. Ce n'est peut-être pas possible, mais j'aimerais essayer.
Je m'excuse d'avoir trop simplifié la question d'origine en ne parlant que d'un type de liste immuable. Toutes les collections ne sont pas aussi auto-descriptives que ImmutableList<T>
:)