web-dev-qa-db-fra.com

Lequel et pourquoi préférez-vous les codes d'exceptions ou de retour?

Ma question est de savoir ce que la plupart des développeurs préfèrent pour la gestion des erreurs, les exceptions ou les codes de retour d'erreur. Veuillez être spécifique à la langue (ou à la famille de langues) et pourquoi vous préférez l'une à l'autre.

Je pose cette question par curiosité. Personnellement, je préfère les codes de retour d'erreur car ils sont moins explosifs et ne forcent pas le code utilisateur à payer la pénalité de performance d'exception s'il ne le souhaite pas.

mise à jour: merci pour toutes les réponses! Je dois dire que même si je n'aime pas l'imprévisibilité du flux de code avec des exceptions. La réponse sur le code de retour (et leurs poignées de frère aîné) ajoute beaucoup de bruit au code.

81
Robert Gould

Pour certains langages (c'est-à-dire C++), la fuite de ressources ne devrait pas être une raison

C++ est basé sur RAII.

Si vous avez du code qui pourrait échouer, retourner ou lancer (c'est-à-dire, la plupart du code normal), alors vous devriez avoir votre pointeur enveloppé dans un pointeur intelligent (en supposant que vous avez un très bon raison de ne pas avoir créé votre objet sur la pile).

Les codes de retour sont plus verbeux

Ils sont verbeux et ont tendance à évoluer vers quelque chose comme:

if(doSomething())
{
   if(doSomethingElse())
   {
      if(doSomethingElseAgain())
      {
          // etc.
      }
      else
      {
         // react to failure of doSomethingElseAgain
      }
   }
   else
   {
      // react to failure of doSomethingElse
   }
}
else
{
   // react to failure of doSomething
}

Au final, votre code est une collection d'instructions identifiées (j'ai vu ce genre de code dans le code de production).

Ce code pourrait bien être traduit en:

try
{
   doSomething() ;
   doSomethingElse() ;
   doSomethingElseAgain() ;
}
catch(const SomethingException & e)
{
   // react to failure of doSomething
}
catch(const SomethingElseException & e)
{
   // react to failure of doSomethingElse
}
catch(const SomethingElseAgainException & e)
{
   // react to failure of doSomethingElseAgain
}

Quel code séparer proprement et traitement des erreurs, qui peut être une chose bonne.

Les codes de retour sont plus fragiles

Si ce n'est pas un avertissement obscur d'un compilateur (voir le commentaire de "phjr"), ils peuvent facilement être ignorés.

Avec les exemples ci-dessus, supposez que quelqu'un oublie de gérer son éventuelle erreur (cela se produit ...). L'erreur est ignorée lorsqu'elle est "renvoyée" et peut éventuellement exploser plus tard (c'est-à-dire un pointeur NULL). Le même problème ne se produira pas avec exception.

L'erreur ne sera pas ignorée. Parfois, vous voulez qu'il n'explose pas, cependant ... Vous devez donc choisir avec soin.

Les codes de retour doivent parfois être traduits

Disons que nous avons les fonctions suivantes:

  • doSomething, qui peut renvoyer un entier appelé NOT_FOUND_ERROR
  • doSomethingElse, qui peut renvoyer un booléen "false" (en cas d'échec)
  • doSomethingElseSagain, qui peut renvoyer un objet Error (avec à la fois les variables __LINE__, __FILE__ et la moitié des variables de la pile.
  • doTryToDoSomethingWithAllThisMess qui, eh bien ... Utilisez les fonctions ci-dessus, et retournez un code d'erreur de type ...

Quel est le type de retour de doTryToDoSomethingWithAllThisMess si l'une de ses fonctions appelées échoue?

Les codes retour ne sont pas une solution universelle

Les opérateurs ne peuvent pas renvoyer de code d'erreur. Les constructeurs C++ ne le peuvent pas non plus.

Les codes de retour signifient que vous ne pouvez pas chaîner des expressions

Le corollaire du point ci-dessus. Et si je veux écrire:

CMyType o = add(a, multiply(b, c)) ;

Je ne peux pas, car la valeur de retour est déjà utilisée (et parfois, elle ne peut pas être modifiée). La valeur de retour devient donc le premier paramètre, envoyé comme référence ... Ou pas.

Les exceptions sont saisies

Vous pouvez envoyer différentes classes pour chaque type d'exception. Les exceptions de ressources (c'est-à-dire par manque de mémoire) devraient être légères, mais tout le reste pourrait être aussi lourd que nécessaire (j'aime l'exception Java me donnant toute la pile).

Chaque prise peut alors être spécialisée.

N'utilisez jamais de catch (...) sans relancer

En règle générale, vous ne devez pas masquer une erreur. Si vous ne relancez pas, au moins, enregistrez l'erreur dans un fichier, ouvrez une boîte de message, peu importe ...

Les exceptions sont ... NUKE

Le problème à l'exception est que leur utilisation excessive produira du code plein d'essais/captures. Mais le problème est ailleurs: qui essaie/attrape son code en utilisant le conteneur STL? Pourtant, ces conteneurs peuvent envoyer une exception.

Bien sûr, en C++, ne laissez jamais une exception quitter un destructeur.

Les exceptions sont ... synchrones

Assurez-vous de les attraper avant qu'ils ne mettent votre fil à genoux ou se propagent dans votre boucle de messages Windows.

La solution pourrait être de les mélanger?

Donc je suppose que la solution est de jeter quand quelque chose devrait pas se produire. Et quand quelque chose peut se produire, utilisez un code retour ou un paramètre pour permettre à l'utilisateur d'y réagir.

Donc, la seule question est "qu'est-ce qui ne devrait pas arriver?"

Cela dépend du contrat de votre fonction. Si la fonction accepte un pointeur, mais spécifie que le pointeur doit être non NULL, alors il est correct de lever une exception lorsque l'utilisateur envoie un pointeur NULL (la question étant, en C++, quand l'auteur de la fonction n'a-t-il pas utilisé des références à la place de pointeurs, mais ...)

Une autre solution serait de montrer l'erreur

Parfois, votre problème est que vous ne voulez pas d'erreurs. Utiliser des exceptions ou des codes de retour d'erreur est cool, mais ... Vous voulez en savoir plus.

Dans mon travail, nous utilisons une sorte de "Assert". Il dépendra, selon les valeurs d'un fichier de configuration, quelles que soient les options de compilation de débogage/libération:

  • enregistrer l'erreur
  • ouvrir une boîte de message avec un "Hé, vous avez un problème"
  • ouvrir une boîte de message avec un "Hé, vous avez un problème, voulez-vous déboguer"

En développement et en test, cela permet à l'utilisateur de localiser le problème exactement quand il est détecté, et non après (lorsqu'un code se soucie de la valeur de retour ou à l'intérieur d'une capture).

Il est facile d'ajouter au code hérité. Par exemple:

void doSomething(CMyObject * p, int iRandomData)
{
   // etc.
}

conduit une sorte de code similaire à:

void doSomething(CMyObject * p, int iRandomData)
{
   if(iRandomData < 32)
   {
      MY_RAISE_ERROR("Hey, iRandomData " << iRandomData << " is lesser than 32. Aborting processing") ;
      return ;
   }

   if(p == NULL)
   {
      MY_RAISE_ERROR("Hey, p is NULL !\niRandomData is equal to " << iRandomData << ". Will throw.") ;
      throw std::some_exception() ;
   }

   if(! p.is Ok())
   {
      MY_RAISE_ERROR("Hey, p is NOT Ok!\np is equal to " << p->toString() << ". Will try to continue anyway") ;
   }

   // etc.
}

(J'ai des macros similaires qui ne sont actives que lors du débogage).

Notez qu'en production, le fichier de configuration n'existe pas, donc le client ne voit jamais le résultat de cette macro ... Mais il est facile de l'activer en cas de besoin.

Conclusion

Lorsque vous codez à l'aide de codes retour, vous vous préparez à l'échec et vous espérez que votre forteresse de tests sera suffisamment sécurisée.

Lorsque vous codez à l'aide d'une exception, vous savez que votre code peut échouer et placez généralement la prise de contre-feu à la position stratégique choisie dans votre code. Mais en général, votre code concerne davantage "ce qu'il doit faire" que "ce que je crains qu'il se produise".

Mais lorsque vous codez, vous devez utiliser le meilleur outil à votre disposition, et parfois, c'est "Ne jamais cacher une erreur et l'afficher le plus tôt possible". La macro dont j'ai parlé ci-dessus suit cette philosophie.

101
paercebal

J'utilise les deux en fait.

J'utilise des codes retour s'il s'agit d'une erreur connue et possible. Si c'est un scénario qui, je le sais, peut arriver et se produira, alors il y a un code qui est renvoyé.

Les exceptions sont utilisées uniquement pour des choses auxquelles je ne m'attends pas.

32
Stephen Wrighton

Selon le chapitre 7 intitulé "Exceptions" dans Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, de nombreuses raisons sont données pour expliquer pourquoi l'utilisation d'exceptions sur les valeurs de retour est nécessaire pour OO frameworks tels que C #.

C'est peut-être la raison la plus convaincante (page 179):

"Les exceptions s'intègrent bien aux langages orientés objet. Les langages orientés objet ont tendance à imposer des contraintes sur les signatures des membres qui ne sont pas imposées par les fonctions dans les langages non OO. Par exemple, dans le cas des constructeurs, les surcharges d'opérateurs et propriétés, le développeur n'a pas le choix dans la valeur de retour. Pour cette raison, il n'est pas possible de standardiser le rapport d'erreur basé sur la valeur de retour pour les frameworks orientés objet. ne méthode de rapport d'erreur, telle que exceptions, qui est hors bande de la signature de méthode est la seule option. "

20
hurst

Ma préférence (en C++ et Python) est d'utiliser des exceptions. Les installations fournies par la langue en font un processus bien défini pour à la fois lever, intercepter et (si nécessaire) relancer les exceptions, ce qui rend le modèle facile à voir et à utiliser. Conceptuellement, c'est plus propre que les codes de retour, dans la mesure où des exceptions spécifiques peuvent être définies par leurs noms et accompagnées d'informations supplémentaires. Avec un code retour, vous êtes limité à la seule valeur d'erreur (sauf si vous souhaitez définir un objet ReturnStatus ou quelque chose).

À moins que le code que vous écrivez soit critique dans le temps, la surcharge associée au déroulement de la pile n'est pas suffisamment importante pour vous inquiéter.

10
Jason Etheridge

Les exceptions ne doivent être renvoyées que lorsque quelque chose se produit auquel vous ne vous attendiez pas.

L'autre point d'exception, historiquement, est que les codes de retour sont intrinsèquement propriétaires, parfois un 0 peut être renvoyé d'une fonction C pour indiquer le succès, parfois -1, ou l'un d'eux pour un échec avec 1 pour un succès. Même lorsqu'elles sont énumérées, les énumérations peuvent être ambiguës.

Les exceptions peuvent également fournir beaucoup plus d'informations, et précisent bien: "Quelque chose ne va pas, voici quoi, une trace de pile et des informations de support pour le contexte"

Cela étant dit, un code de retour bien énuméré peut être utile pour un ensemble connu de résultats, un simple "heres n résultats de la fonction, et il a simplement fonctionné de cette façon"

7
johnc

En Java, j'utilise (dans l'ordre suivant):

  1. Conception par contrat (s'assurer que les conditions préalables sont remplies avant d'essayer quoi que ce soit qui pourrait échouer). Cela attrape la plupart des choses et je renvoie un code d'erreur pour cela.

  2. Renvoyer des codes d'erreur lors du traitement du travail (et effectuer une restauration si nécessaire).

  3. Des exceptions, mais celles-ci sont utilisées niquement pour des choses inattendues.

5
paxdiablo

Un excellent conseil que j'ai reçu de The Pragmatic Programmer était quelque chose dans le sens de "votre programme devrait être capable d'exécuter toutes ses fonctionnalités principales sans utiliser d'exceptions du tout".

4
Smashery

J'ai écrit un blog post à ce sujet il y a quelque temps.

Les frais généraux liés au lancement d'une exception ne devraient pas jouer de rôle dans votre décision. Si vous le faites bien, après tout, une exception est exceptionnelle .

4
Thomas

Les codes de retour échouent presque à chaque fois au test " Pit of Success ".

  • Il est beaucoup trop facile d'oublier de vérifier un code retour et d'avoir une erreur de red-harging plus tard.
  • Les codes de retour n'ont aucune des informations de débogage sur eux comme la pile d'appels, les exceptions internes.
  • Les codes de retour ne se propagent pas, ce qui, avec le point ci-dessus, a tendance à générer une journalisation de diagnostic excessive et entrelacée au lieu de se connecter à un emplacement centralisé (gestionnaires d'exceptions au niveau de l'application et du thread).
  • Les codes de retour ont tendance à générer du code désordonné sous la forme de blocs "si" imbriqués
  • Le temps passé par le développeur à déboguer un problème inconnu qui aurait autrement été une exception évidente (fosse de succès) IS cher).
  • Si l'équipe derrière C # n'avait pas prévu d'exceptions pour régir le flux de contrôle, les exceptions ne seraient pas saisies, il n'y aurait pas de filtre "quand" sur les instructions catch, et il n'y aurait pas besoin de l'instruction 'throw' sans paramètre .

Concernant les performances:

  • Les exceptions peuvent être coûteuses en calcul RELATIVES au fait de ne pas lancer du tout, mais elles sont appelées EXCEPTIONS pour une raison. Les comparaisons de vitesse parviennent toujours à supposer un taux d'exception de 100%, ce qui ne devrait jamais être le cas. Même si une exception est 100 fois plus lente, dans quelle mesure cela importe-t-il vraiment si cela ne se produit que 1% du temps?
  • À moins que nous ne parlions d'arithmétique à virgule flottante pour les applications graphiques ou quelque chose de similaire, les cycles de processeur sont bon marché par rapport au temps de développement.
  • Le coût dans une perspective temporelle porte le même argument. Par rapport aux requêtes de base de données ou aux appels de service Web ou aux chargements de fichiers, le temps d'application normal éclipsera le temps d'exception. Les exceptions étaient presque sous-MICROsecond en 2006
    • J'ose quiconque travaille en .net, pour configurer votre débogueur pour qu'il interrompt toutes les exceptions et désactiver uniquement mon code et voir combien d'exceptions se produisent déjà que vous ne connaissez même pas.
4
b_levitt

Je n'aime pas les codes de retour, car ils provoquent la prolifération du modèle suivant dans tout votre code

CRetType obReturn = CODE_SUCCESS;
obReturn = CallMyFunctionWhichReturnsCodes();
if (obReturn == CODE_BLOW_UP)
{
  // bail out
  goto FunctionExit;
}

Bientôt, un appel de méthode composé de 4 appels de fonction s'enrichit de 12 lignes de gestion des erreurs. Certaines ne se produiront jamais. Les cas If et Switch abondent.

Les exceptions sont plus propres si vous les utilisez bien ... pour signaler des événements exceptionnels .. après quoi le chemin d'exécution ne peut pas continuer. Ils sont souvent plus descriptifs et informatifs que les codes d'erreur.

Si vous avez plusieurs états après un appel de méthode qui doivent être traités différemment (et ne sont pas des cas exceptionnels), utilisez des codes d'erreur ou des paramètres de sortie. Bien que personnellement, j'ai trouvé que c'était rare ..

J'ai un peu chassé le contre-argument de la "pénalité de performance". Plus dans le monde C++/COM mais dans les nouveaux langages, je pense que la différence n'est pas si grande. Dans tous les cas, quand quelque chose explose, les problèmes de performances sont relégués au second plan :)

4
Gishu

Je crois que les codes de retour ajoutent au bruit du code. Par exemple, j'ai toujours détesté l'apparence du code COM/ATL en raison des codes retour. Il devait y avoir une vérification HRESULT pour chaque ligne de code. Je considère que le code de retour d'erreur est l'une des mauvaises décisions prises par les architectes de COM. Cela rend difficile le regroupement logique du code, ainsi la révision du code devient difficile.

Je ne suis pas sûr de la comparaison des performances lorsqu'il y a une vérification explicite du code retour à chaque ligne.

3
rpattabi

Avec tout compilateur décent ou environnement d'exécution, les exceptions n'entraînent pas de pénalité importante. Cela ressemble plus ou moins à une instruction GOTO qui passe au gestionnaire d'exceptions. De plus, le fait d'avoir des exceptions capturées par un environnement d'exécution (comme la JVM) permet d'isoler et de corriger un bogue beaucoup plus facilement. Je prendrai une NullPointerException dans Java sur un segfault en C n'importe quel jour.

3
Kyle Cronin

J'utilise des exceptions dans python dans des circonstances à la fois exceptionnelles et non exceptionnelles.

Il est souvent agréable de pouvoir utiliser une exception pour indiquer que "la demande n'a pas pu être effectuée", par opposition au renvoi d'une valeur d'erreur. Cela signifie que vous/toujours/savez que la valeur de retour est le bon type, au lieu de arbitrairement None ou NotFoundSingleton ou quelque chose. Voici un bon exemple où je préfère utiliser un gestionnaire d'exceptions au lieu d'une conditionnelle à la valeur de retour.

try:
    dataobj = datastore.fetch(obj_id)
except LookupError:
    # could not find object, create it.
    dataobj = datastore.create(....)

L'effet secondaire est que lorsqu'un datastore.fetch (obj_id) est exécuté, vous n'avez jamais à vérifier si sa valeur de retour est None, vous obtenez immédiatement cette erreur gratuitement. Ceci est contraire à l'argument, "votre programme devrait être capable d'exécuter toutes ses fonctionnalités principales sans utiliser d'exceptions du tout".

Voici un autre exemple de cas où les exceptions sont "exceptionnellement" utiles, afin d'écrire du code pour gérer le système de fichiers qui n'est pas soumis aux conditions de concurrence.

# wrong way:
if os.path.exists(directory_to_remove):
    # race condition is here.
    os.path.rmdir(directory_to_remove)

# right way:
try: 
    os.path.rmdir(directory_to_remove)
except OSError:
    # directory didn't exist, good.
    pass

Un appel système au lieu de deux, aucune condition de concurrence. C'est un mauvais exemple, car cela échouera évidemment avec une OSError dans plus de circonstances que le répertoire n'existe pas, mais c'est une solution "assez bonne" pour de nombreuses situations étroitement contrôlées.

3
Jerub

Je préfère utiliser des exceptions pour la gestion des erreurs et les valeurs de retour (ou paramètres) comme résultat normal d'une fonction. Cela donne un schéma de gestion des erreurs facile et cohérent et s'il est fait correctement, il rend le code beaucoup plus propre.

2
Trent

L'une des grandes différences est que les exceptions vous obligent à gérer une erreur, tandis que les codes retour d'erreur peuvent être décochés.

Les codes de retour d'erreur, s'ils sont largement utilisés, peuvent également provoquer un code très laid avec beaucoup de tests if similaires à ce formulaire:

if(function(call) != ERROR_CODE) {
    do_right_thing();
}
else {
    handle_error();
}

Personnellement, je préfère utiliser des exceptions pour les erreurs qui DEVRAIENT ou DOIVENT être traitées par le code appelant, et n'utiliser des codes d'erreur que pour les "défaillances attendues" où le retour de quelque chose est réellement valide et possible.

2
Daniel Bruce

Il existe de nombreuses raisons de préférer les exceptions au code retour:

  • Habituellement, pour plus de lisibilité, les gens essaient de minimiser le nombre de déclarations de retour dans une méthode. Ce faisant, les exceptions empêchent d'effectuer un travail supplémentaire dans un état incoorect, et empêchent ainsi potentiellement d'endommager davantage de données.
  • Les exceptions sont généralement plus verbeuses et plus facilement extensibles que la valeur de retour. Supposons qu'une méthode renvoie un nombre naturel et que vous utilisez des nombres négatifs comme code de retour lorsqu'une erreur se produit, si la portée de votre méthode change et retourne maintenant des entiers, vous devrez modifier tous les appels de méthode au lieu de simplement peaufiner un peu l'éxéption.
  • Les exceptions permettent de séparer plus facilement la gestion des erreurs de comportement normal. Ils permettent de garantir que certaines opérations fonctionnent en quelque sorte comme une opération atomique.
2
gizmo

Les exceptions ne concernent pas la gestion des erreurs, OMI. Les exceptions ne sont que cela; des événements exceptionnels auxquels vous ne vous attendiez pas. À utiliser avec prudence, dis-je.

Les codes d'erreur peuvent être OK, mais renvoyer 404 ou 200 à partir d'une méthode est mauvais, IMO. Utilisez plutôt des énumérations (.Net), ce qui rend le code plus lisible et plus facile à utiliser pour les autres développeurs. De plus, vous n'avez pas à maintenir un tableau sur les nombres et les descriptions.

Aussi; le motif try-catch-finally est un anti-motif dans mon livre. Essayer-finalement peut être bon, essayer-attraper peut aussi être bon mais essayer-attraper-finalement n'est jamais bon. try-finally peut souvent être remplacé par une instruction "using" (modèle IDispose), ce qui est mieux IMO. Et Try-catch où vous attrapez réellement une exception que vous êtes capable de gérer est bon, ou si vous faites ceci:

try{
    db.UpdateAll(somevalue);
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}

Donc, tant que vous laissez l'exception continuer à bouillonner, c'est OK. Un autre exemple est le suivant:

try{
    dbHasBeenUpdated = db.UpdateAll(somevalue); // true/false
}
catch (ConnectionException ex) {
    logger.Exception(ex, "Connection failed");
    dbHasBeenUpdated = false;
}

Ici, je gère réellement l'exception; ce que je fais en dehors du try-catch lorsque la méthode de mise à jour échoue est une autre histoire, mais je pense que mon argument a été avancé. :)

Pourquoi est-ce que try-catch-finalement est un anti-modèle? Voici pourquoi:

try{
    db.UpdateAll(somevalue);
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}
finally {
    db.Close();
}

Que se passe-t-il si l'objet db a déjà été fermé? Une nouvelle exception est levée et doit être gérée! C'est mieux:

try{
    using(IDatabase db = DatabaseFactory.CreateDatabase()) {
        db.UpdateAll(somevalue);
    }
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}

Ou, si l'objet db n'implémente pas IDisposable, procédez comme suit:

try{
    try {
        IDatabase db = DatabaseFactory.CreateDatabase();
        db.UpdateAll(somevalue);
    }
    finally{
        db.Close();
    }
}
catch (DatabaseAlreadyClosedException dbClosedEx) {
    logger.Exception(dbClosedEx, "Database connection was closed already.");
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}

C'est mes 2 cents quand même! :)

2
noocyte

J'utilise uniquement des exceptions, pas de codes retour. Je parle de Java ici.

La règle générale que je respecte est que si j'ai une méthode appelée doFoo(), il s'ensuit que si elle ne fait pas "foo", pour ainsi dire, alors quelque chose d'exceptionnel s'est produit et une exception doit être levée.

1
SCdF

Une chose que je crains à propos des exceptions, c'est que lever une exception va gâcher le flux de code. Par exemple, si vous le faites

void foo()
{
  MyPointer* p = NULL;
  try{
    p = new PointedStuff();
    //I'm a module user and  I'm doing stuff that might throw or not

  }
  catch(...)
  {
    //should I delete the pointer?
  }
}

Ou pire encore, si je supprimais quelque chose que je n'aurais pas dû, mais que je me faisais attraper avant de faire le reste du nettoyage. Lancer a mis beaucoup de poids sur le pauvre utilisateur à mon humble avis.

1
Robert Gould

Ma règle générale dans l'argument exception/code retour:

  • Utilisez des codes d'erreur lorsque vous avez besoin de localisation/internationalisation - dans .NET, vous pouvez utiliser ces codes d'erreur pour référencer un fichier de ressources qui affichera ensuite l'erreur dans la langue appropriée. Sinon, utilisez des exceptions
  • N'utilisez des exceptions que pour les erreurs vraiment exceptionnelles. Si c'est quelque chose qui arrive assez souvent, utilisez un booléen ou un code d'erreur enum.
1
Jon Limjap

J'ai un ensemble simple de règles:

1) Utilisez les codes de retour pour les choses auxquelles vous vous attendez à ce que votre correspondant immédiat réagisse.

2) Utilisez des exceptions pour les erreurs dont la portée est plus large et dont on peut raisonnablement s'attendre à ce qu'elles soient gérées par plusieurs niveaux au-dessus de l'appelant afin que la connaissance de l'erreur n'ait pas à se propager à travers plusieurs couches, ce qui rend le code plus complexe.

Dans Java je n'ai utilisé que des exceptions non contrôlées, les exceptions vérifiées finissent par n'être qu'une autre forme de code retour et d'après mon expérience, la dualité de ce qui pourrait être "renvoyé" par un appel de méthode était généralement plus une gêne plutôt qu'une aide.

Je ne trouve pas les codes de retour moins moches que les exceptions. À l'exception, vous avez la try{} catch() {} finally {} où, comme pour les codes retour, vous avez if(){}. J'avais l'habitude de craindre les exceptions pour les raisons données dans le post; vous ne savez pas si le pointeur doit être effacé, qu'avez-vous. Mais je pense que vous avez les mêmes problèmes en ce qui concerne les codes de retour. Vous ne connaissez pas l'état des paramètres, sauf si vous connaissez certains détails sur la fonction/méthode en question.

Quoi qu'il en soit, vous devez gérer l'erreur si possible. Vous pouvez tout aussi facilement laisser une exception se propager au niveau supérieur qu'ignorer un code retour et laisser le programme segfault.

J'aime l'idée de renvoyer une valeur (énumération?) Pour les résultats et une exception pour un cas exceptionnel.

1
Jonathan Adelson

Pour un langage comme Java, j'irais avec Exception car le compilateur donne une erreur de temps de compilation si les exceptions ne sont pas gérées, ce qui force la fonction appelante à gérer/lever les exceptions.

Pour Python, je suis plus en conflit. Il n'y a pas de compilateur, il est donc possible que l'appelant ne gère pas l'exception levée par la fonction menant à des exceptions d'exécution. Si vous utilisez des codes retour, vous pourriez avoir un comportement inattendu s'il n'est pas géré correctement et si vous utilisez des exceptions, vous pouvez obtenir des exceptions d'exécution.

0
2ank3th