Philosophie du keyword C# out

par sandreo Email

Il y a quelques semaines de cela j'ai fait tourner Reshaper 2.0 sur mon code afin de supprimer les namespaces non utilisés, variables initialisées inutilement et autres petites choses, résultant de refactorings successifs sans cleanup.

Tout se passe pour le mieux jusqu'à ce que mon collègue qui développe une partie de l'assembly me dit : "Ton outil c'est très bien mais il a changé la sémantique de ma fonction..."|-|



En effet Resharper avait changé ce type de code:

public enum BufferType
{
    Stream,
    Buffer,
    Undefined
}
public void Read(out int length , out BufferType type)
{
    length = 0;
    type = BufferType.Undefined;
    Byte[] buff = new Byte[256];
    length = this.DoSomething();
    if(...)
       type = BufferType.Stream;
    else
        type = BufferType.Buffer;
}


en

public void Read(out int length , out BufferType type)
{
    Byte[] buff = new Byte[256];
    length = this.DoSomething();
    if(...)
       type = BufferType.Stream;
    else
        type = BufferType.Buffer;
}


Et oui resharper avait supprimé les 2 affectations en début de méthode. Et là commenca une longue et âpre discussion....

Son argumentation était basée sur le fait que l'utilisation du keyword out obligeait de fournir une valeur de retour correcte dans tous les cas. Donc pour le garantir ca il fallait qu'il initialise ces 2 paramètres dès le début de la méthode. Ceci n'est effectivement pas tout à fait faux.



Mais le compilateur C# vérifie que toutes les branches de code de la méthode vont garantir l'affectations des variables out, donc à priori pas besoin d'affecter d'entrée celles-ci.

Et là tombe l'argument massue! Et oui mais en cas d'erreur, plus précisement la méthode DoSomething lève une exception.... Si tu n'as pas affecté tes variables en début de méthode et bien au sortir tes variables ne le seront pas... Je suis resté dubitatif 88|

Comment peut on imaginer initialiser des variables (toutes out quelles soient) lorsqu'une erreur se produit. Lorsqu'une exception est levée (et qu'elle ne peut pas être traitée dans la méthode) c'est forcément une rupture de contrat. Vouloir transporter des informations grâce aux parametres out pour traiter l'erreur est forcément en opposition avec les bonnes pratiques de gestion d'erreur

Donc pour résumer on laisse le compilo faire son travail et en cas d'erreur c'est à l'appelant de traiter l'erreur et donc d'initialiser les valeurs comme son context le lui indique.

D'autres avis sur la question?

Adresse de trackback pour cet article

This is a captcha-picture. It is used to prevent mass-access by robots.
Please enter the characters from the image above. (case insensitive)

7 commentaires

Commentaire de: Simon Mourier [Visiteur] · http://www.codefluent.com
Mon avis, c'est que 1) ces outils sont dangereux et qu'il vaut souvent mieux utiliser son cerveau, et 2) il faut eviter d'utiliser les paramètres out qui sont très anti OOP. D'ailleurs, je crois qu'en Java ça n'existe pas.

Je suis surpris d'ailleurs que resharper ne rajoute pas des accolades
if(...)
{
type = BufferType.Stream;
}
else
{
type = BufferType.Buffer;
}
}

car ne pas mettre les accolades, ça peut mener à des risques d'erreurs plus tard lorsqu'on va maintenir le code.
28.11.06 @ 09:11
Commentaire de: Amethyste [Visiteur]
Je suis de l'avis de Simon Mounier concernant les accolades, je suis même convaincu que cette syntaxe ne devrait même pas être possible.

concernant le out.
C'est vrai que cela me laisse moi aussi perplexe quand à son intérêt. Mais puisqu'il est là, autant effectivement essayer de dégager de bonnes pratiques d'utilisation.

Supposons que l'on renplace les out par un objet disons Toto contenant les champs type et length. Une exception survient dans DoSomething().

Si une exception survient lorsque l'on appelle une méthode, on ne s'attend pas à obtenir un type de retour valide. D'ailleurs l'exécution du code s'arrêtera là et .NET partira à la recherche d'un catch quand au type de retour il restera non définit.

Pour les même raison je ne vois pas pourquoi cela devrait être différent pour nos valeureux paramètres

s'il y a une exception, c'est que ça n'a pas fonctionné.
28.11.06 @ 09:59
Commentaire de: Fabien Bezagu [Visiteur] · http://fabien.bezagu.free.fr
Si j'avais dû faire le refactoring manuellement, j'aurais fait exactement comme Resharper (avec les accolades en plus).

En effet, il n'est pas envisageable de lire les paramètres de retour si une exception a été levé. Je rejoins donc Amethyste : "S'il y a une exception, c'est que ça n'a pas fonctionné."
28.11.06 @ 10:47
Commentaire de: sandreo [Membre] Email
Ok Ok pour les allocades... je sais que Amethyste est un vaillant defenseur de la l'accolade a la ligne suivante (et Simon egalement ):-) Mais hier soir j'ai eu comme une fleme de les mettre ;-)

Enfin sur le fait que ces outils soient dangereux je suis mitige, on va dire 50/50 et j"appelle un ami! Sous certains aspects comme le cleanup de namespace, et les varaibles non utilisees c"est assez interessant je trouve. Il me semble que ca ameliore la lisibilite du code et donc la qualite. Mais cela ne veut pas dire qu'il faille prendre son resultat comme une verite ultime. Un code review est toujours le bien venu apres.

Mais bon apres comment fait on de bonnes code review.... ca c"est une autre affaire.

Pour les exceptions je suis bien d"accord avec moi meme et donc avec Amethyse, et heureusement que nous ne sommes pas seul au monde! Mais il reste encore bcp de monde a eduquer.....

28.11.06 @ 10:53
Commentaire de: Thibaut Barrère [Visiteur] · http://www.dotnetguru2.org/tbarrere
Deux petites notes pour ma part:
- le refactoring (qu'il soit manuel ou automatisé) prend toute sa valeur lorsque le code est couvert par des tests unitaires (typiquement ici un test unitaire qui teste un cas de bordure, qui lève une exception)... Quand on a une bonne couverture de tests, on refactore sans pitié, et on est prévenu quand la sémantique change, car un test ou deux passent au rouge.
- pas de problème pour moi avec le refactoring (qu'il soit manuel ou automatisé, bis!), mais avant tout commit/checkin, un diff et une revue de code sont très précieux.
28.11.06 @ 16:38
Commentaire de: Nip [Visiteur]
Je suis d'accord avec l'avis general concernant l'utilisation du out.

2 autres petites choses
-Concernant la mise en forme. Il est possible de configurer Resharper pour avoir le retour a la ligne et l'ajout d'accolade quand ca manque. Pour reformater du code qu'on a maintenir, c'est sans prix et ameliore la visibilite en 2 coups de cuillere a pot.
-Concernant le refactoring automatique; j'ai du mal a voir la dangerosite de l'outil (que ca soit couple ou non aux TU): auriez vous un exemple autre que celui presente par sandreo?
29.11.06 @ 18:26
Commentaire de: Amethyste [Visiteur]
Je me demande vraiment pourquoi VS ne permet pas de nettoyer les using et les références excédentaires.

Ca fait tout de même plus pro de livrer un code impécable, personne n'accepterai que son plombier ne nettoie pas une fois le boulot terminé, pour les même raisons j'aime bien prendre le temps de nettoyer mon code.

30.11.06 @ 11:48

Laisser un commentaire


Votre adresse email ne sera pas révélée sur ce site.

Votre URL sera affichée.
(Les retours à la ligne deviennent des <br />)
(Nom, e-mail & site Web)
(Autoriser les utilisateurs à vous contacter par un formulaire de message (votre adresse email ne sera not révélée.))
This is a captcha-picture. It is used to prevent mass-access by robots.
Please enter the characters from the image above. (case insensitive)