Question Une fonction devrait-elle avoir une seule déclaration de retour?


Y a-t-il de bonnes raisons pour lesquelles il est préférable d'avoir une seule déclaration de retour dans une fonction?

Ou est-ce correct de revenir d'une fonction dès qu'il est logique de le faire, ce qui signifie qu'il peut y avoir plusieurs instructions de retour dans la fonction?


781


origine


Réponses:


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

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

... peut être rendu plus lisible (IMHO) 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.


743



Personne n'a mentionné ou cité Code complet 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 revenir quand il améliore la lisibilité. Dans certaines routines, une fois que vous connaissez la réponse, vous voulez la renvoyer immédiatement à la routine d'appel. Si la routine est définie de telle sorte qu'elle ne nécessite aucun nettoyage, ne pas retourner immédiatement signifie que vous devez écrire plus de code.


355



Je dirais qu'il serait incroyablement imprudent de décider arbitrairement contre plusieurs points de sortie car j'ai trouvé que la technique était utile dans la pratique encore et encoreen fait j'ai souvent code existant refactorisé à 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. Autant que je sache, la critique de plusieurs points de sortie est un point de vue plutôt archaïque ces temps-ci.


229



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

Avec la théorie du «point de sortie unique», vous obtenez inévitablement 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 maintenant, disons plus tard que vous devez revenir en arrière et ajouter une opération entre 1 et 2. Vous devez mettre en retrait à peu près toute la fonction de panique, et bonne chance en vous assurant vos conditions if / else et vos accolades sont correctement mises en correspondance.

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


191



Programmation structurée dit que vous devriez seulement avoir une déclaration de retour par fonction. C'est pour limiter la complexité. Beaucoup de gens comme Martin Fowler soutiennent qu'il est plus simple d'écrire des fonctions avec plusieurs déclarations de retour. Il présente cet argument dans le classique refactoring 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 de la programmation structurée stricte adhèrent à des déclarations de rendement unique par fonction.


72



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

"était d'empêcher la confusion possible   en sautant dans et hors de nombreux   endroits dans la même routine. Il a fait   bon sens lorsqu'il est appliqué à FORTRAN ou   programmes de langue d'assemblage écrits   avec beaucoup de données mondiales où même   comprendre quelles déclarations étaient   exécuté était un travail difficile ... avec de petites méthodes et surtout des données locales, il est inutilement conservateur. "

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


62



Dans une fonction qui n'a pas d'effets secondaires, il n'y a pas de bonne raison d'avoir plus d'un seul retour et vous devriez 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), donc vous écrivez dans un style impératif, en utilisant l'instruction return comme une commande pour arrêter l'exécution.

En d'autres termes, quand c'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 trouvez en train d'écrire plusieurs couches de conditions imbriquées, il y a probablement un moyen de refactoriser cela, en utilisant une liste de prédicats par exemple. Si vous trouvez que vos ifs et elses sont très éloignés syntaxiquement, vous voudrez peut-être décomposer cela en plus petites fonctions. Un bloc conditionnel qui couvre plus d'un écran de texte est difficile à lire.

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


61



Je l'ai vu dans les normes de codage pour C ++ qui étaient un hang-over de C, comme si vous n'aviez pas RAII ou toute autre gestion automatique de la mémoire, alors vous devez nettoyer pour chaque retour, ce qui signifie couper et coller du nettoyage ou d'un goto (logiquement le même que 'finally' dans les langages gérés), les deux étant considérés comme mauvais. Si vos pratiques consistent à utiliser des pointeurs et des collections intelligents en C ++ ou dans un autre système de mémoire automatique, il n'y a pas de raison majeure pour cela, et il s'agit uniquement de la lisibilité, et plus d'un jugement.


43



Je penche pour l'idée que les déclarations de retour dans le milieu de la fonction sont mauvais. Vous pouvez utiliser des retours pour construire quelques clauses de garde en haut de la fonction, et bien sûr dire au compilateur ce qu'il faut retourner à la fin de la fonction sans problème, mais retourne dans le milieu de la fonction peut être facile à manquer et peut rendre la fonction plus difficile à interpréter.


40



Y a-t-il de bonnes raisons pour lesquelles il est préférable d'avoir une seule déclaration de retour dans une fonction?

Oui, il y a:

  • Le point de sortie unique donne un excellent endroit pour affirmer vos post-conditions.
  • Pouvoir mettre un point d'arrêt du débogueur sur le 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 à un seul retour entraîne une complexité, il est alors intéressant de refactoriser des fonctions plus petites, plus générales et plus faciles à comprendre.
  • Si vous êtes dans une langue sans destructeur ou si vous n'utilisez pas RAII, alors un seul retour réduit le nombre de places à 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 si imbriquées. Il y a presque toujours une troisième solution très linéaire (pas d'imbrication profonde) avec un seul point de sortie.

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

Pour être clair, je ne dis pas que c'est toujours mal d'avoir plusieurs retours. Mais étant donné des solutions par ailleurs équivalentes, il y a beaucoup de bonnes raisons de préférer celle avec un seul retour.


38