Dans quelle mesure 'var' et l'opérateur de coalescence nul '??' être diverti sans entraver la lisibilité?

23

Je sais que le titre de la question est très subjectif, mais j'ai été confronté à l'utilisation de l' ??opérateur par mes pairs, où en même temps je n'étais pas très content / à l'aise d'appliquer le varnouveau code à venir.

L'argument donné pour utiliser l' ??opérateur était, il enlève la lisibilité dans le code.

Ma question est la suivante: la même chose ne se produit-elle pas lorsque vous commencez à utiliser var?

Numan
la source
49
Si un "développeur" ne peut pas comprendre l' ??opérateur de fusion nulle après son explication, il ne devrait pas être autorisé à proximité du code de production.
CaffGeek
12
Je suggère que nous changions l'opérateur de ?? à IfNullThen. ? peut être IfSoChoose,: est ElseChoose. + est Ajouter. - est Soustraire, à moins qu'il ne soit unaire, alors c'est Négatif. - est divisé entre DecrementBeforeUsing et DecrementAfterUsing. En C ++, vous pouvez le faire avec des macros.
Lee Louviere
7
@Xaade: C'est ironique n'est-ce pas? ... droite? ... Dieu que ce soit ironique (et je suis athée).
Steven Jeuris
10
@StevenJeuris C'est peut-être du sarcasme , mais ce n'est pas de l' ironie .
Kirk Broadhurst
1
@KirkBroadhurst: Je suis corrigé , j'ai toujours confondu ces deux-là.
Steven Jeuris

Réponses:

53

Opérateur coalescent nul (??)

Personnellement, je ne vois aucun inconvénient à utiliser cet opérateur. Considérez les trois exemples de code suivants, des nouveaux opérateurs «faciles» aux «complexes».

Sans magie:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

Opérateur ternaire:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

Coalescence nulle:

string name = null;
Console.WriteLine( name ?? "No name set." );

La raison pour laquelle ces opérateurs ont été inventés est qu'ils représentent des opérations de programmation très courantes . Ne pas vouloir les utiliser parce que vous n'y êtes pas habitué, c'est simplement être têtu . Les langages évoluent, les fonctionnalités évoluent, apprenez à les utiliser!

mot-clé var

J'ai une opinion quelque peu différente sur le mot-clé var. Le type d'une variable donne souvent des informations supplémentaires sur votre code. Je trouve que masquer le type en utilisant le mot clé var rend parfois le code moins lisible. Vous savez moins à quoi vous attendre sans utiliser la saisie semi-automatique ou en survolant les identifiants pour voir ce qu'ils sont réellement. À mon avis, cela se traduit par du code qui est plus lent à lire / écrire.

J'utilise le mot-clé lorsque je trouve que le type ne donne pas beaucoup d'informations supplémentaires.

  • Principalement dans les boucles foreach , que j'ai apprises de Resharper car c'est un paramètre là-bas. La plupart du temps, vous savez quel type de collection vous parcourez, vous savez donc que vous attendez des éléments de cette collection.
  • Requêtes Linq . Les résultats des requêtes linq sont souvent des types génériques très complexes. L'affichage de ce type fait plus de mal que de bien.
  • Noms de caractères longs qui sont simplement initialisés avec leur constructeur. Vous pouvez déjà dire quel est le type en regardant le constructeur.

Comme exemple pour la dernière déclaration:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();
Steven Jeuris
la source
24
Ce dernier exemple est exactement lorsque le mot-clé var peut exceller. Imaginez que le code soit jonché tout au long de votre code. Factory.CreateSomeTyperetourne IEnumerable<SomeType>. Un jour, pour une raison quelconque, il change pour revenir SomeType[]. Si vous avez utilisé var, c'est juste une recompilation.
pdr
1
J'ai eu cet exemple dans le mauvais sens, puis je suis allé chercher de la nourriture. Numpty! Un meilleur exemple serait d'utiliser le vôtre. Et si des Factory.CreateSomeType()changements pour retourner un ISomeType?
pdr
4
@pdr: Cela signifie très probablement que l'interface a également changé et que le comportement doit également être ajusté / ajouté. S'il s'agit d'un simple changement de nom, vous avez bien entendu un changement de nom automatisé. Si le «contrat» change, je préfère voir mon code casser afin que je puisse voir si je dois ajuster quelque chose ou non.
Steven Jeuris
2
Je pense qu'il est beaucoup plus probable que si le retour d'un type concret devient le retour d'une interface, il autorise simplement d'autres types de béton avec la même interface (cohérent avec le modèle Factory). Mais si le contrat change, alors votre code se cassera - bien que vous ne le trouviez que dans quelques cas où cela compte plutôt que partout.
pdr
1
@ Tom Hawtin, nous savons tous qu'il est inévitable d'éviter nullcomplètement. De plus, plus je recherche d'alternatives null, plus je me rends compte que l'utilisation nullest parfois la solution la plus propre. Mon exemple donné n'est pas si mauvais que ça à mon humble avis, et je trouve que c'est une utilisation appropriée des types nullables.
Steven Jeuris
16

var permet un code moins détaillé, ce qui augmente la lisibilité. À mon avis, la lisibilité ne doit pas être mesurée par le nombre de détails que vous voyez, mais par le nombre de détails masqués au premier coup d'œil. Outre les exemples Linq, var permet de taper du canard au niveau du code source, dans l'exemple suivant:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

Peu importe quel est le type d'étiquette tant qu'il fournit la propriété Text?

Codisme
la source
Quelqu'un essayant de comprendre s'il s'agit par exemple d'une étiquette Winforms ou d'une étiquette WPF.
Steven Jeuris
14
@Steven Jeuris: c'est généralement une information de contexte connue. Sinon, vous approchez le code d'une manière incorrecte.
Codism
Quelqu'un qui veut savoir s'il s'agit d'une étiquette WPF par défaut ou d'une étiquette personnalisée? :)
Steven Jeuris
14
1. Cette personne devrait-elle vraiment s'en soucier, tant qu'il s'agit d'une étiquette avec une propriété Text? 2. Si c'est l'un des rares cas dont ils ont vraiment une bonne raison de s'en soucier, demandez à Intellisense. 3. S'ils éditent du code dans un IDE sans Intellisense, ils ont probablement des inconvénients bien plus importants que 'var' :)
KutuluMike
4
Quelqu'un avec un mauvais sens de l'abstraction.
Jim Balter
16

Je n'ai pas de commentaires sérieux sur l' ??opérateur, car je n'ai jamais utilisé une langue avec un tel opérateur. En ce qui concerne var, les gens programment dans des langages comme Ruby, Python, Perl et PHP qui ont tout le temps un typage totalement implicite. Les autochtones de ces langues se rendent compte que le type formel d'une variable est généralement un bruit non pertinent. Vous êtes plus intéressé par ce que la variable peut faire , c'est-à-dire son interface structurelle / canard.

De même, je programme principalement en D. D est typé statiquement mais a le automot - clé, qui est équivalent à var. Il est considéré idiomatique de l'utiliser partout, sauf si vous voyez un besoin spécifique de mettre l'accent sur le type de quelque chose pour le lecteur ou (via une conversion implicite) le compilateur. Sauf occasionnellement lorsqu'il est utilisé comme type de retour de fonction (cela est autorisé en D), je ne l'ai jamais trouvé gênant la lisibilité, car je pense principalement en termes d'interfaces structurelles / canards, pas de types formels / nominatifs, lorsque je programme.

En outre, à mon humble avis, utiliser varpartout où c'est possible est un bon exemple de SEC. Le type de quelque chose doit être spécifié dans un et un seul endroit, puis être propagé automatiquement chaque fois qu'il doit être propagé. Si vous utilisez varet que le type formel de la variable doit changer à un moment donné, les modifications nécessaires seront automatiquement propagées partout où cela est nécessaire par le compilateur tant que le programme est toujours correct, plutôt que le programmeur doive changer manuellement chaque instance . C'est une bonne chose (TM).

dsimcha
la source
13

Je pense que c'est une question pour l'équipe à la fin. Si ce n'est lisible par personne d'autre dans mon équipe, je ne l'utiliserai pas, bien que je puisse essayer plusieurs fois de les convaincre avec des exemples, ou en soulignant des abréviations analogiques (telles que + =) qu'ils trouvent plus lisibles.

Cependant, si je travaille seul, je trouve ?? et var parfaitement lisible sans limites. Même

var a = b ?? c ?? d ?? e ?? "";

est assez clair pour moi.

Les opérateurs ternaires et dynamicsont une question différente, bien sûr.

pdr
la source
4
J'utiliserais `String.Empty 'ici.
Job
1
@Job, en toute honnêteté, moi aussi. J'allais mettre quelque chose dans cette chaîne, alors je ne pouvais penser à rien :)
pdr
4
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Lee Louviere
2
@Xaade Vous ne pouvez jamais être assez sûr. Mais vraiment, utiliser String.Empty ou "" est une préférence personnelle. J'utilise "" car il est plus court ...
Carra
12
@Xaade - si String.Emptyjamais il revient null, nous allons avoir un tas de code cassé.
Jesse C. Slicer
10

L'argument donné pour utiliser ?? opérateur était, il enlève la lisibilité dans le code.

En y réfléchissant brièvement, ce commentaire me dit que la personne qui fait le commentaire ne le comprend pas aussi bien qu'il le devrait. C'est probablement vrai dans certaines situations, mais dans l'ensemble, je n'écarte pas quelque chose que l'équipe C # a évidemment pensé être suffisamment important pour ajouter en raison de la "lisibilité". Je mets cela dans la même catégorie de if(boolean_object)vs if(boolean_object == true). Certaines personnes soutiennent que le second est plus lisible, mais en réalité, il s'agit simplement d'ajouter du code supplémentaire pour que quelqu'un puisse le lire / taper, et dans certaines situations, cela peut être plus déroutant (pensez if(boolean_object != false))

Ma question est la suivante: la même chose ne se produit-elle pas lorsque vous commencez à utiliser var?

L'équipe C # vous a permis de ne pas définir quelque chose dont vous savez ce que ce sera. Sauf si j'ai absolument besoin de définir ce que va être une variable (soit il est absolument important qu'un objet retourné soit de type x, soit il n'est vraiment pas lisible), j'utilise var. var x = "MY_STRING";Je sais que c'est une chaîne de le regarder. En vérité, je ne me soucie pas vraiment que ce soit une chaîne tant qu'elle fait ce que j'ai besoin de faire. La définition du type de variable est pour moi, pas celle du compilateur. Si quelque chose ne va pas, le compilateur me dira quand il fonctionnera si j'ai le mauvais type de variable.

kemiller2002
la source
0

À varmon avis, le mot-clé est mieux utilisé dans les situations pour lesquelles il a été introduit à l'origine - les requêtes LINQ. Dans ces requêtes, le type du résultat renvoyé a souvent un gros nom alambiqué qui est difficile à déterminer à l'avance et n'aide pas le lecteur à comprendre ce que fait votre code.

Cependant, faire var text = "Some text " + variableName + "some more text." est juste paresseux.

EDIT: @Jorg Vous avez sauté sur une réponse volontairement simpliste mais n'avez rien ajouté à la discussion. OK, que diriez-vous de cela pour un meilleur exemple: var items = doc.DocumentElement.FirstChild.ChildNodes;si vous pouvez comprendre le type à partir de cela, je vous donnerai un cookie.

Josh Earl
la source
18
Si vous ne pouvez pas comprendre que "Some text "c'est un string, alors vous avez beaucoup plus de problèmes à vous soucier que le nombre de vars dans votre code.
Jörg W Mittag
3
Le problème n'est pas var; le problème est le nom de variable merdique "items". Si vous utilisez un bon nom de variable, il n'y a rien de mal à cela var.
Kyralessa
3
Je suppose (sans regarder) que les éléments sont une collection de nœuds XML, que je m'attends à avoir toutes les propriétés et méthodes d'une collection de nœuds XML, et c'est vraiment tout ce que je dois savoir.
KutuluMike
Si vous avez besoin de savoir quel type représente la var et que vous ne pouvez pas le dire immédiatement en regardant, passez simplement la souris dessus. Ne prend pas beaucoup de temps pour le faire.
scrwtp
1
"est juste paresseux" - Ce n'est pas un argument contre. En fait, ce n'est pas du tout intelligent.
Jim Balter
0

J'ai un problème fondamental avec l'utilisation de var.

Dans cet exemple, tout est côte à côte, mais le problème est vraiment avec les grandes solutions avec des bibliothèques ou des projets partagés.

Considère ceci:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

Que se passe-t-il si GetMeAnObject est modifié, par quelqu'un d'autre, pour répondre à leurs besoins?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

La méthode MainProgram aura une grosse erreur rouge sur .PerformOperation (). Qu'est-il arrivé? PerformOperation fonctionnait parfaitement bien avant. Nous regardons les méthodes sur l'Object et il vient de disparaître sans laisser de trace. C'était là la dernière fois, et nous avons besoin de cette méthode. Vous pourriez passer beaucoup de temps à courir après votre queue et à essayer de comprendre pourquoi, si MyFirstObject a une méthode appelée PerformOperation, elle ne peut plus être vue maintenant. Tout le monde "sait" que GetMeAnObject renvoie un MyFirstObject, il est donc inutile de vérifier cela.

Si vous aviez explicitement tapé theObject, vous auriez alors une erreur de transtypage non valide sur la ligne qui appelle GetMeAnObject, et il serait aveuglément évident que GetMeAnObject renvoie un type qui n'est pas celui que vous attendez.

En bref, une déclaration explicite signifie que vous savez ce que signifient les erreurs. Une conversion non valide signifie que vous attendiez un type et qu'un autre type a été renvoyé. Un membre non reconnu signifie que le membre n'a pas été reconnu.

Hugh Phoenix-Hulme
la source
10
Un collègue a effectué un changement de code non couvert par les tests, et vous pensez que le problème est var? On ne peut pas s'attendre à ce que le langage protège contre ce genre de comportement - et s'ils avaient modifié MyFirstObject directement? Cela aurait quand même cassé, mais aucune syntaxe n'aurait pu vous en sauver. Je considérerais cela comme une force var, même: et si au lieu de retourner MySecondObject, vous retourniez maintenant IMyFirstObject à la place?
Phoshi
2
"Tout le monde" sait "que GetMeAnObject renvoie un MyFirstObject, il est donc inutile de vérifier cela." Je ne peux pas vraiment penser à un scénario de programmation où je dépendrais réellement de ma mémoire de ce que GetMeAnObject si je débogue. Si j'avais vérifié que PerformOperation n'était pas là, j'aurais vu le code et non c'est pour une autre classe. Si dans un IDE la classe ferait apparaître l'instance, je regarde le type de l'objet. En fait, lorsque le compilateur me dit l'erreur, il dirait «la classe MySecondObject n'a aucune opération PerformOperation». Comment est-ce que tout le monde sait?
Muhammad Alkarouri