Question

Existe-t-il de bonnes raisons pour lesquelles il est préférable de n'avoir qu'une seule instruction return dans une fonction ?

Ou est-il acceptable de revenir d'une fonction dès que cela est logiquement correct, ce qui signifie qu'il peut y avoir de nombreuses instructions return dans la fonction ?

Était-ce utile?

La solution

J'ai souvent plusieurs déclarations au début d'une méthode à revenir pour des situations "faciles".Par exemple, ceci :

public void DoStuff(Foo foo)
{
    if (foo != null)
    {
        ...
    }
}

...peut être rendu plus lisible (à mon humble avis) comme ceci :

public void DoStuff(Foo foo)
{
    if (foo == null) return;

    ...
}

Alors oui, je pense que c'est bien d'avoir plusieurs "points de sortie" d'une fonction/méthode.

Autres conseils

Personne n'a mentionné ou cité Code terminé donc je vais le faire.

17.1 retour

Minimiser le nombre de retours dans chaque routine.Il est plus difficile de comprendre une routine si, en la lisant en bas, vous ignorez la possibilité qu'elle soit revenue quelque part au-dessus.

Utiliser un retour quand cela améliore la lisibilité.Dans certaines routines, une fois que vous connaissez la réponse, vous souhaitez la renvoyer immédiatement à la routine appelante.Si la routine est définie de telle manière qu'elle ne nécessite aucun nettoyage, ne pas revenir immédiatement signifie que vous devez écrire plus de code.

Je dirais qu'il serait incroyablement imprudent de décider arbitrairement de plusieurs points de sortie, car j'ai trouvé la technique utile dans la pratique. encore et encore, en fait j'ai souvent code existant refactorisé vers plusieurs points de sortie pour plus de clarté.Nous pouvons comparer les deux approches ainsi : -

string fooBar(string s, int? i) {
  string ret = "";
  if(!string.IsNullOrEmpty(s) && i != null) {
    var res = someFunction(s, i);

    bool passed = true;
    foreach(var r in res) {
      if(!r.Passed) {
        passed = false;
        break;
      }
    }

    if(passed) {
      // Rest of code...
    }
  }

  return ret;
}

Comparez cela au code où plusieurs points de sortie sont permis:-

string fooBar(string s, int? i) {
  var ret = "";
  if(string.IsNullOrEmpty(s) || i == null) return null;

  var res = someFunction(s, i);

  foreach(var r in res) {
      if(!r.Passed) return null;
  }

  // Rest of code...

  return ret;
}

Je pense que ce dernier est considérablement plus clair.Pour autant que je sache, la critique des points de sortie multiples est un point de vue plutôt archaïque de nos jours.

Je travaille actuellement sur une base de code sur laquelle deux des personnes qui y travaillent souscrivent aveuglément à la théorie du "point de sortie unique" et je peux vous dire que par expérience, c'est une pratique horrible et horrible.Cela rend le code extrêmement difficile à maintenir et je vais vous montrer pourquoi.

Avec la théorie du « point de sortie unique », on se retrouve inévitablement avec un code qui ressemble à ceci :

function()
{
    HRESULT error = S_OK;

    if(SUCCEEDED(Operation1()))
    {
        if(SUCCEEDED(Operation2()))
        {
            if(SUCCEEDED(Operation3()))
            {
                if(SUCCEEDED(Operation4()))
                {
                }
                else
                {
                    error = OPERATION4FAILED;
                }
            }
            else
            {
                error = OPERATION3FAILED;
            }
        }
        else
        {
            error = OPERATION2FAILED;
        }
    }
    else
    {
        error = OPERATION1FAILED;
    }

    return error;
}

Non seulement cela rend le code très difficile à suivre, mais disons maintenant que vous devrez revenir en arrière et ajouter une opération entre 1 et 2.Vous devez mettre en retrait à peu près toute la foutue fonction, et bonne chance pour vous assurer que toutes vos conditions et accolades if/else correspondent correctement.

Cette méthode rend la maintenance du code extrêmement difficile et sujette aux erreurs.

Programmation structurée dit que vous ne devriez avoir qu'une seule instruction return par fonction.Ceci afin de limiter la complexité.De nombreuses personnes, comme Martin Fowler, soutiennent qu'il est plus simple d'écrire des fonctions avec plusieurs instructions return.Il présente cet argument dans le classique refactorisation livre qu'il a écrit.Cela fonctionne bien si vous suivez ses autres conseils et écrivez de petites fonctions.Je suis d'accord avec ce point de vue et seuls les puristes stricts de la programmation structurée adhèrent à des instructions de retour uniques par fonction.

Comme le note Kent Beck à propos des clauses de garde dans Modèles de mise en œuvre faire en sorte qu'une routine ait un seul point d'entrée et de sortie...

"devait empêcher la confusion possible lors du saut dans et hors de nombreux endroits dans la même routine.Cela avait du bon sens lorsqu'il est appliqué aux programmes de Fortran ou de langue d'assemblage écrits avec de nombreuses données mondiales où même la compréhension des déclarations exécutées a été un travail difficile ...avec de petites méthodes et principalement des données locales, c’est inutilement conservateur. »

Je trouve qu'une fonction écrite avec des clauses de garde est beaucoup plus facile à suivre qu'un long groupe de clauses imbriquées. if then else déclarations.

Dans une fonction qui n'a pas d'effets secondaires, il n'y a aucune bonne raison d'avoir plus d'un seul retour et vous devez les écrire dans un style fonctionnel.Dans une méthode avec des effets secondaires, les choses sont plus séquentielles (indexées dans le temps), vous écrivez donc dans un style impératif, en utilisant l'instruction return comme commande pour arrêter l'exécution.

Autrement dit, lorsque cela est possible, privilégiez ce style

return a > 0 ?
  positively(a):
  negatively(a);

sur ceci

if (a > 0)
  return positively(a);
else
  return negatively(a);

Si vous vous retrouvez à écrire plusieurs couches de conditions imbriquées, il existe probablement un moyen de les refactoriser, en utilisant par exemple une liste de prédicats.Si vous constatez que vos si et vos autres sont syntaxiquement très éloignés, vous souhaiterez peut-être les diviser en fonctions plus petites.Un bloc conditionnel qui s’étend sur plus d’un écran de texte est difficile à lire.

Il n’existe pas de règle absolue qui s’applique à toutes les langues.Quelque chose comme avoir une seule instruction return ne rendra pas votre code bon.Mais un bon code aura tendance à vous permettre d’écrire vos fonctions de cette façon.

Je l'ai vu dans les normes de codage pour C++ qui étaient un héritage du C, comme si vous n'aviez pas RAII ou autre gestion automatique de la mémoire, vous devez alors nettoyer pour chaque retour, ce qui signifie soit couper-coller du nettoyage ou d'un goto (logiquement identique à "finalement" dans les langages gérés), tous deux considérés comme de mauvaise forme.Si vos pratiques consistent à utiliser des pointeurs et des collections intelligents en C++ ou dans un autre système de mémoire automatique, alors il n'y a pas de raison valable pour cela, et cela devient une question de lisibilité et davantage une question de jugement.

Je penche pour l'idée que les déclarations return dans le milieu de la fonction sont mauvais.Vous pouvez utiliser return pour créer quelques clauses de garde en haut de la fonction, et bien sûr indiquer au compilateur ce qu'il doit renvoyer à la fin de la fonction sans problème, mais renvoie dans le milieu de la fonction peut être facile à manquer et peut rendre la fonction plus difficile à interpréter.

Existe-t-il de bonnes raisons pour lesquelles il est préférable de n'avoir qu'une seule instruction return dans une fonction ?

Oui, il y a:

  • Le point de sortie unique constitue un excellent endroit pour faire valoir vos post-conditions.
  • Pouvoir mettre un point d'arrêt du débogueur sur le seul retour à la fin de la fonction est souvent utile.
  • Moins de retours signifie moins de complexité.Le code linéaire est généralement plus simple à comprendre.
  • Si essayer de simplifier une fonction en un seul retour entraîne de la complexité, cela incite à refactoriser des fonctions plus petites, plus générales et plus faciles à comprendre.
  • Si vous êtes dans un langage sans destructeurs ou si vous n'utilisez pas RAII, alors un seul retour réduit le nombre d'endroits à nettoyer.
  • Certaines langues nécessitent un seul point de sortie (par exemple, Pascal et Eiffel).

La question est souvent posée comme une fausse dichotomie entre des déclarations multiples ou des déclarations if profondément imbriquées.Il existe presque toujours une troisième solution très linéaire (pas d'imbrication profonde) avec un seul point de sortie.

Mise à jour:Apparemment Les directives MISRA favorisent la sortie unique, aussi.

Pour être clair, je ne dis pas que c'est toujours c'est mal d'avoir plusieurs retours.Mais à solutions par ailleurs équivalentes, il y a de nombreuses bonnes raisons de préférer celle à rendement unique.

Avoir un seul point de sortie offre un avantage dans le débogage, car il vous permet de définir un seul point d'arrêt à la fin d'une fonction pour voir quelle valeur va réellement être renvoyée.

En général, j'essaie de n'avoir qu'un seul point de sortie d'une fonction.Il arrive cependant que cela finisse par créer un corps de fonction plus complexe que nécessaire, auquel cas il est préférable d'avoir plusieurs points de sortie.Il doit vraiment s'agir d'un « jugement » basé sur la complexité qui en résulte, mais l'objectif doit être d'avoir le moins de points de sortie possible sans sacrifier la complexité et la compréhensibilité.

Non parce que nous ne vivons plus dans les années 70.Si votre fonction est suffisamment longue pour que plusieurs retours posent problème, elle est trop longue.

(Outre le fait que toute fonction multiligne dans un langage avec des exceptions aura de toute façon plusieurs points de sortie.)

Ma préférence irait à une sortie unique, à moins que cela ne complique vraiment les choses.J'ai constaté que dans certains cas, plusieurs points existants peuvent masquer d'autres problèmes de conception plus importants :

public void DoStuff(Foo foo)
{
    if (foo == null) return;
}

En voyant ce code, je demanderais immédiatement :

  • Est-ce que « foo » est toujours nul ?
  • Si oui, combien de clients de « DoStuff » ont déjà appelé la fonction avec un « foo » nul ?

Selon les réponses à ces questions, il se pourrait que

  1. le contrôle est inutile car il n'est jamais vrai (c.-à-d.ça devrait être une affirmation)
  2. la vérification est très rarement vraie et il peut donc être préférable de modifier ces fonctions d'appelant spécifiques car elles devraient probablement prendre une autre action de toute façon.

Dans les deux cas ci-dessus, le code peut probablement être retravaillé avec une assertion pour garantir que « foo » n'est jamais nul et que les appelants concernés ont changé.

Il y a deux autres raisons (spécifiques, je pense, au code C++) pour lesquelles plusieurs existent peuvent en fait avoir un négatif affecter.Il s'agit de la taille du code et des optimisations du compilateur.

Un objet C++ non POD dans la portée à la sortie d'une fonction verra son destructeur appelé.Lorsqu'il existe plusieurs instructions return, il se peut que la portée des objets soit différente et que la liste des destructeurs à appeler soit donc différente.Le compilateur doit donc générer du code pour chaque instruction return :

void foo (int i, int j) {
  A a;
  if (i > 0) {
     B b;
     return ;   // Call dtor for 'b' followed by 'a'
  }
  if (i == j) {
     C c;
     B b;
     return ;   // Call dtor for 'b', 'c' and then 'a'
  }
  return 'a'    // Call dtor for 'a'
}

Si la taille du code est un problème, cela vaut peut-être la peine d’être évité.

L'autre problème concerne "l'optimisation de la valeur de retour nommée" (alias Copy Elision, ISO C++ '03 12.8/15).C++ permet à une implémentation d'ignorer l'appel du constructeur de copie si elle le peut :

A foo () {
  A a1;
  // do something
  return a1;
}

void bar () {
  A a2 ( foo() );
}

En prenant simplement le code tel quel, l'objet « a1 » est construit dans « foo », puis sa construction de copie sera appelée pour construire « a2 ».Cependant, l'élision de copie permet au compilateur de construire « a1 » au même endroit sur la pile que « a2 ».Il n'est donc pas nécessaire de "copier" l'objet au retour de la fonction.

Plusieurs points de sortie compliquent le travail du compilateur pour tenter de détecter cela, et au moins pour une version relativement récente de VC++, l'optimisation n'a pas eu lieu là où le corps de la fonction avait plusieurs retours.Voir Optimisation de la valeur de retour nommée dans Visual C++ 2005 pour plus de détails.

Avoir un seul point de sortie réduit Complexité cyclomatique et donc, en théorie, réduit la probabilité que vous introduisiez des bugs dans votre code lorsque vous le modifiez.La pratique tend cependant à suggérer qu’une approche plus pragmatique est nécessaire.J'ai donc tendance à viser un seul point de sortie, mais à permettre à mon code d'en avoir plusieurs si cela est plus lisible.

Je me force à n'en utiliser qu'un return déclaration, car elle générera dans un sens une odeur de code.Laisse-moi expliquer:

function isCorrect($param1, $param2, $param3) {
    $toret = false;
    if ($param1 != $param2) {
        if ($param1 == ($param3 * 2)) {
            if ($param2 == ($param3 / 3)) {
                $toret = true;
            } else {
                $error = 'Error 3';
            }
        } else {
            $error = 'Error 2';
        }
    } else {
        $error = 'Error 1';
    }
    return $toret;
}

(Les conditions sont arbitraires...)

Plus il y a de conditions, plus la fonction est grande, plus elle est difficile à lire.Donc, si vous êtes sensible à l'odeur du code, vous vous en rendrez compte et souhaiterez refactoriser le code.Deux solutions possibles sont :

  • Retours multiples
  • Refactorisation en fonctions distinctes

Retours multiples

function isCorrect($param1, $param2, $param3) {
    if ($param1 == $param2)       { $error = 'Error 1'; return false; }
    if ($param1 != ($param3 * 2)) { $error = 'Error 2'; return false; }
    if ($param2 != ($param3 / 3)) { $error = 'Error 3'; return false; }
    return true;
}

Fonctions séparées

function isEqual($param1, $param2) {
    return $param1 == $param2;
}

function isDouble($param1, $param2) {
    return $param1 == ($param2 * 2);
}

function isThird($param1, $param2) {
    return $param1 == ($param2 / 3);
}

function isCorrect($param1, $param2, $param3) {
    return !isEqual($param1, $param2)
        && isDouble($param1, $param3)
        && isThird($param2, $param3);
}

Certes, c'est plus long et un peu compliqué, mais en refactorisant la fonction de cette façon, nous avons

  • créé un certain nombre de fonctions réutilisables,
  • a rendu la fonction plus lisible par l'homme, et
  • les fonctions se concentrent sur la raison pour laquelle les valeurs sont correctes.

Je dirais que vous devriez en avoir autant que nécessaire, ou tout ce qui rend le code plus propre (comme clauses de garde).

Personnellement, je n'ai jamais entendu/vu de "meilleures pratiques" dire que vous ne devriez avoir qu'une seule déclaration de retour.

Pour la plupart, j'ai tendance à quitter une fonction le plus tôt possible en fonction d'un chemin logique (les clauses de garde en sont un excellent exemple).

Je crois que plusieurs retours sont généralement bons (dans le code que j'écris en C#).Le style à retour unique est un vestige de C.Mais vous ne codez probablement pas en C.

Aucune loi n'exige qu'un seul point de sortie pour une méthode dans tous les langages de programmation.Certaines personnes insistent sur la supériorité de ce style, et parfois l'élèvent au rang de « règle » ou de « loi », mais cette croyance n'est étayée par aucune preuve ou recherche.

Plusieurs styles de retour peuvent être une mauvaise habitude dans le code C, où les ressources doivent être explicitement désallouées, mais les langages tels que Java, C#, Python ou JavaScript qui ont des constructions telles que le garbage collection automatique et try..finally blocs (et using blocs en C#), et cet argument ne s'applique pas - dans ces langages, il est très rare d'avoir besoin d'une désallocation manuelle centralisée des ressources.

Il existe des cas où un seul retour est plus lisible, et d'autres où il ne l'est pas.Voyez si cela réduit le nombre de lignes de code, rend la logique plus claire ou réduit le nombre d'accolades et de retraits ou de variables temporaires.

Par conséquent, utilisez autant de retours que cela convient à votre sensibilité artistique, car il s’agit d’un problème de mise en page et de lisibilité, et non technique.

j'en ai parlé ceci plus en détail sur mon blog.

Il y a de bonnes choses à dire sur l’existence d’un point de sortie unique, tout comme il y a de mauvaises choses à dire sur l’inévitable "flèche" programmation qui en résulte.

Si j'utilise plusieurs points de sortie lors de la validation des entrées ou de l'allocation des ressources, j'essaie de placer toutes les « sorties d'erreur » de manière très visible en haut de la fonction.

Les deux Programmation spartiate article du "SSDSLPedia" et le point de sortie à fonction unique L'article du "Portland Pattern Repository's Wiki" contient des arguments perspicaces à ce sujet.Bien sûr, il y a aussi ce post à considérer.

Si vous voulez vraiment un seul point de sortie (dans n'importe quel langage ne prenant pas en charge les exceptions), par exemple afin de libérer des ressources en un seul endroit, je trouve que l'application minutieuse de goto est bonne ;voir par exemple cet exemple plutôt artificiel (compressé pour économiser de l'espace sur l'écran) :

int f(int y) {
    int value = -1;
    void *data = NULL;

    if (y < 0)
        goto clean;

    if ((data = malloc(123)) == NULL)
        goto clean;

    /* More code */

    value = 1;
clean:
   free(data);
   return value;
}

Personnellement, en général, je n'aime pas plus la programmation de flèches que les points de sortie multiples, bien que les deux soient utiles lorsqu'ils sont appliqués correctement.Le mieux, bien sûr, est de structurer votre programme de manière à ce qu’il n’exige ni l’un ni l’autre.Décomposer votre fonction en plusieurs morceaux est généralement utile :)

Bien que ce faisant, je constate que je me retrouve de toute façon avec plusieurs points de sortie, comme dans cet exemple, où une fonction plus grande a été décomposée en plusieurs fonctions plus petites :

int g(int y) {
  value = 0;

  if ((value = g0(y, value)) == -1)
    return -1;

  if ((value = g1(y, value)) == -1)
    return -1;

  return g2(y, value);
}

En fonction du projet ou des directives de codage, la plupart du code passe-partout pourrait être remplacé par des macros.En remarque, cette décomposition rend les fonctions g0, g1 et g2 très faciles à tester individuellement.

Évidemment, dans un langage OO et prenant en charge les exceptions, je n'utiliserais pas d'instructions if comme celle-là (ou pas du tout, si je pouvais m'en sortir avec peu d'effort), et le code serait beaucoup plus simple.Et non-flèche.Et la plupart des retours non définitifs seraient probablement des exceptions.

En bref;

  • Peu de retours valent mieux que de nombreux retours
  • Plus d'un retour vaut mieux que d'énormes flèches, et clauses de garde sont généralement ok.
  • Les exceptions pourraient/devraient probablement remplacer la plupart des « clauses de garde » lorsque cela est possible.

Vous connaissez l'adage - La beauté est dans les yeux du spectateur.

Certaines personnes ne jurent que par NetBeans et certains par IDÉE IntelliJ, certains par Python et certains par PHP.

Dans certains magasins, vous risquez de perdre votre emploi si vous insistez pour faire ceci :

public void hello()
{
   if (....)
   {
      ....
   }
}

La question est toute une question de visibilité et de maintenabilité.

Je suis accro à l'utilisation de l'algèbre booléenne pour réduire et simplifier la logique et l'utilisation des machines à états.Cependant, d'anciens collègues pensaient que mon utilisation de « techniques mathématiques » dans le codage n'était pas adaptée, car elle ne serait ni visible ni maintenable.Et ce serait une mauvaise pratique.Désolé les gens, les techniques que j'utilise sont très visibles et maintenables pour moi - car lorsque je reviendrai au code six mois plus tard, je comprendrais clairement le code plutôt que de voir un gâchis de spaghettis proverbiaux.

Hé mon pote (comme le disait un ancien client), fais ce que tu veux tant que tu sais comment le réparer quand j'ai besoin que tu le répares.

Je me souviens qu'il y a 20 ans, un de mes collègues a été licencié pour avoir employé ce qu'on appellerait aujourd'hui développement agile stratégie.Il avait un plan progressif méticuleux.Mais son manager lui criait : « Vous ne pouvez pas proposer progressivement des fonctionnalités aux utilisateurs !Vous devez vous en tenir au cascade" Sa réponse au responsable a été que le développement incrémental serait plus précis selon les besoins du client.Il croyait au développement adapté aux besoins des clients, mais le responsable croyait au codage selon les « exigences du client ».

Nous sommes souvent coupables d'avoir rompu la normalisation des données, MVP et MVC frontières.Nous inline au lieu de construire une fonction.Nous prenons des raccourcis.

Personnellement, je pense que PHP est une mauvaise pratique, mais qu'est-ce que j'en sais.Tous les arguments théoriques se résument à essayer de respecter un ensemble de règles

Qualité = précision, maintenabilité et rentabilité.

Toutes les autres règles passent au second plan.Et bien sûr, cette règle ne s’efface jamais :

La paresse est la vertu d'un bon programmeur.

J'ai tendance à utiliser des clauses de garde pour revenir plus tôt et sinon quitter à la fin d'une méthode.La règle d'entrée et de sortie unique a une signification historique et s'est avérée particulièrement utile lorsqu'il s'agissait de code existant qui s'étendait sur 10 pages A4 pour une seule méthode C++ avec plusieurs retours (et de nombreux défauts).Plus récemment, une bonne pratique acceptée consiste à conserver des méthodes restreintes, ce qui rend les sorties multiples moins un obstacle à la compréhension.Dans l’exemple Kronoz suivant copié ci-dessus, la question est de savoir ce qui se passe dans // Reste du code...?:

void string fooBar(string s, int? i) {

  if(string.IsNullOrEmpty(s) || i == null) return null;

  var res = someFunction(s, i);

  foreach(var r in res) {
      if(!r.Passed) return null;
  }

  // Rest of code...

  return ret;
}

Je me rends compte que l'exemple est quelque peu artificiel mais je serais tenté de refactoriser le pour chaque boucle dans une instruction LINQ qui pourrait alors être considérée comme une clause de garde.Encore une fois, dans un exemple artificiel, l'intention du code n'est pas apparente et uneFonction() peut avoir d’autres effets secondaires ou le résultat peut être utilisé dans le // Reste du code....

if (string.IsNullOrEmpty(s) || i == null) return null;
if (someFunction(s, i).Any(r => !r.Passed)) return null;

Donnant la fonction refactorisée suivante :

void string fooBar(string s, int? i) {

  if (string.IsNullOrEmpty(s) || i == null) return null;
  if (someFunction(s, i).Any(r => !r.Passed)) return null;

  // Rest of code...

  return ret;
}

Une bonne raison à laquelle je peux penser est la maintenance du code :vous avez un seul point de sortie.Si vous souhaitez changer le format du résultat,..., c'est juste beaucoup plus simple à mettre en œuvre.De plus, pour le débogage, vous pouvez simplement y coller un point d'arrêt :)

Cela dit, j'ai déjà dû travailler dans une bibliothèque où les normes de codage imposaient « une instruction return par fonction », et j'ai trouvé cela assez difficile.J'écris beaucoup de code de calcul numérique, et il y a souvent des « cas particuliers », donc le code a fini par être assez difficile à suivre...

Plusieurs points de sortie conviennent pour des fonctions suffisamment petites, c'est-à-dire une fonction qui peut être visualisée sur une seule longueur d'écran dans son intégralité.Si une fonction longue comprend également plusieurs points de sortie, c'est le signe que la fonction peut être davantage découpée.

Ceci dit j'évite les fonctions à sorties multiples sauf en cas d'absolue nécessité.J'ai ressenti des bugs dus à un retour parasite dans une ligne obscure dans des fonctions plus complexes.

J'ai travaillé avec des normes de codage terribles qui vous imposaient un seul chemin de sortie et le résultat est presque toujours des spaghettis non structurés si la fonction est tout sauf triviale - vous vous retrouvez avec de nombreuses pauses et des continuations qui ne font que gêner.

Un point de sortie unique - toutes choses égales par ailleurs - rend le code beaucoup plus lisible.Mais il y a un piège :construction populaire

resulttype res;
if if if...
return res;

est un faux, "res=" n'est pas beaucoup mieux que "return".Il a une seule instruction return, mais plusieurs points où la fonction se termine réellement.

Si vous avez une fonction avec plusieurs retours (ou "res="s), c'est souvent une bonne idée de la diviser en plusieurs fonctions plus petites avec un seul point de sortie.

Ma politique habituelle est de n'avoir qu'une seule instruction return à la fin d'une fonction, à moins que la complexité du code ne soit considérablement réduite en en ajoutant d'autres.En fait, je suis plutôt fan d'Eiffel, qui applique la seule règle de retour en n'ayant pas d'instruction return (il y a juste une variable 'result' créée automatiquement pour y mettre votre résultat).

Il existe certainement des cas où le code peut être rendu plus clair avec plusieurs retours que ne le serait la version évidente sans eux.On pourrait affirmer que des retouches supplémentaires sont nécessaires si vous avez une fonction trop complexe pour être compréhensible sans plusieurs instructions return, mais il est parfois bon d'être pragmatique sur de telles choses.

Si vous obtenez plusieurs retours, il se peut qu'il y ait un problème avec votre code.Sinon, je serais d'accord que parfois il est agréable de pouvoir revenir de plusieurs endroits dans un sous-programme, surtout quand cela rend le code plus propre.

Perl6 :Mauvais exemple

sub Int_to_String( Int i ){
  given( i ){
    when 0 { return "zero" }
    when 1 { return "one" }
    when 2 { return "two" }
    when 3 { return "three" }
    when 4 { return "four" }
    ...
    default { return undef }
  }
}

ce serait mieux écrit comme ça

Perl6 :Bon exemple

@Int_to_String = qw{
  zero
  one
  two
  three
  four
  ...
}
sub Int_to_String( Int i ){
  return undef if i < 0;
  return undef unless i < @Int_to_String.length;
  return @Int_to_String[i]
}

Notez que ce n'est qu'un exemple rapide

Je vote pour le retour unique à la fin à titre indicatif.Cela aide un gestion courante du nettoyage du code ...Par exemple, jetez un œil au code suivant…

void ProcessMyFile (char *szFileName)
{
   FILE *fp = NULL;
   char *pbyBuffer = NULL:

   do {

      fp = fopen (szFileName, "r");

      if (NULL == fp) {

         break;
      }

      pbyBuffer = malloc (__SOME__SIZE___);

      if (NULL == pbyBuffer) {

         break;
      }

      /*** Do some processing with file ***/

   } while (0);

   if (pbyBuffer) {

      free (pbyBuffer);
   }

   if (fp) {

      fclose (fp);
   }
}

C'est probablement une perspective inhabituelle, mais je pense que quiconque croit que plusieurs instructions return doivent être privilégiées n'a jamais eu à utiliser un débogueur sur un microprocesseur ne prenant en charge que 4 points d'arrêt matériels.;-)

Bien que les problèmes de "code fléché" soient tout à fait corrects, un problème qui semble disparaître lors de l'utilisation de plusieurs instructions return concerne la situation où vous utilisez un débogueur.Vous n'avez pas de position fourre-tout pratique pour mettre un point d'arrêt afin de garantir que vous verrez la sortie et donc la condition de retour.

Plus vous avez d’instructions return dans une fonction, plus cette méthode est complexe.Si vous vous demandez si vous avez trop d’instructions return, vous voudrez peut-être vous demander si vous avez trop de lignes de code dans cette fonction.

Mais non, il n’y a rien de mal avec une/plusieurs instructions return.Dans certains langages, c'est une meilleure pratique (C++) que dans d'autres (C).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top