Pourquoi l'option / peut-être considérée comme une bonne idée et les exceptions vérifiées ne le sont pas?

23

Certains langages de programmation comme par exemple Scala ont le concept de Optiontypes (également appelés Maybe), qui peuvent contenir ou non une valeur.

D'après ce que j'ai lu à leur sujet, ils sont largement considérés comme un moyen supérieur de traiter ce problème null, car ils forcent explicitement le programmeur à considérer les cas où il pourrait ne pas y avoir de valeur au lieu de simplement exploser pendant l'exécution.

Les exceptions vérifiées en Java semblent en revanche être considérées comme une mauvaise idée, et Java semble être le seul langage largement utilisé qui les implémente. Mais l'idée derrière eux semble être quelque peu similaire au Optiontype, pour forcer explicitement le programmeur à faire face au fait qu'une exception pourrait être levée.

Existe-t-il des problèmes supplémentaires avec les exceptions cochées que les Optiontypes n'ont pas? Ou ces idées ne sont-elles pas aussi similaires que je le pense, et il y a de bonnes raisons de forcer une gestion explicite des options et non des exceptions?

Scientifique fou
la source
Voir également le Either e atype de données.
4
À propos des exceptions vérifiées: en tant qu'utilisateur d'une multitude de bibliothèques Java open source et internes avec une base de code évolutive et des documents manquants / obsolètes, je frémis à l'idée que Java n'applique pas certaines exceptions à déclarer explicitement. Ce serait un cauchemar d'erreurs d'exécution non gérées apparaissant aux mauvais endroits, de manière inattendue. Et Java7 rend enfin la gestion des exceptions presque saine d'esprit, se débarrassant d'une grande partie du vieux fouillis d'essayage.
hyde

Réponses:

24

Parce que les Options sont composables. Il y a beaucoup de méthodes utiles sur Optionqui vous permettent d'écrire du code concis, tout en permettant un contrôle précis du débit: map, flatMap, toList, flattenet plus encore. Cela est dû au fait qu'il Options'agit d'un type particulier de monade, certains objets que nous savons très bien composer. Si vous n'aviez pas ces méthodes et que vous deviez toujours mettre en correspondance les modèles Optionou appeler isDefinedsouvent, elles ne seraient pas aussi utiles.

Au lieu de cela, bien que les exceptions vérifiées ajoutent une certaine sécurité, vous ne pouvez pas faire grand-chose d'autre que les attraper ou les laisser bouillonner dans la pile (avec le passe-partout ajouté dans la déclaration de type).

Andrea
la source
1
Les exceptions vérifiées se composent plus ou moins de la même manière ... La différence entre try {/* bunch of complex code involving calls to 50 different methods that may throw SomeCheckedException */} catch(SomeCheckedException e) {/* operation failed, do something */}et fromMaybe someDefaultValue (something >>= otherThing >>= ...50 other functions that may return Nothing...)c'est quoi exactement? Autre que le fait que le premier vous donne plus de détails sur ce qui a mal tourné.
user253751
14

Bien que liés, les exceptions et les objets Maybe ne traitent pas le même type de problèmes.

Exceptions

Les exceptions brillent vraiment lorsque vous devez gérer de manière non locale une situation exceptionnelle (qui dans certains cas se trouve être une erreur). Par exemple, vous analysez un fichier csv et vous souhaitez vous protéger contre les lignes dont le formatage est incorrect. L'endroit où vous trouvez que quelque chose ne va pas peut être des appels de fonction loin de l'itération de ligne. Si vous lancez une exception au niveau le plus profond (où vous découvrez le problème de formatage), vous pouvez l'attraper dans la boucle, consigner l'erreur et passer à la ligne suivante. Vous n'avez rien à modifier dans le reste du code.

L'exception cochée ajoute beaucoup de peine car toutes les fonctions intermédiaires doivent déclarer le type jetable. La fonctionnalité va à l'encontre de l'objectif initial, c'est pourquoi elles ne sont pas populaires de nos jours.

Peut-être des objets

Peut-être que les objets doivent être choisis lorsque vous êtes capable de gérer localement un "échec". En ce sens, ils remplacent un code retour + une API par référence ou un type nullable.

L'avantage de l'objet Maybe est que vous déclarez explicitement que quelque chose ne va pas. Dans haskell, un objet non peut-être doit avoir une valeur, sinon le programme ne compilera pas.

Le problème avec les types nullables est que vous devez vérifier la valeur null tout le temps pour être absolument sûr. L'état "quelque chose pourrait ne pas fonctionner" est celui par défaut.

Le problème avec les codes retour + passer par les ref ref est qu'ils sont moins lisibles pour la plupart des gens.

Simon Bergot
la source
1
@MattFenwick merci pour les commentaires. Pourquoi pensez-vous que l'exemple csv n'a pas de sens? L'OP ne demande pas vraiment de techniques d'évitement de passe-partout, et j'ai le sentiment que le vocabulaire tel que foncteur applicatif et monades peut être trop technique pour cette question.
Simon Bergot
1
Je voudrais souligner qu'avec Java (pas sûr des autres langages avec des exceptions vérifiées), les IDE se chargent d'ajouter et d'élaguer les lancers et de mettre à jour la partie passe-partout des commentaires javadoc. Donc, au moins, cette partie n'est pas la peine et certainement pas la douleur. Que ce soit une douleur ou une aubaine ou quelque chose entre les deux lors de la conception d'API, c'est une autre affaire ...
hyde
5
@hyde: Ce n'est pas parce qu'un IDE peut automatiser la génération de passe-partout inutile que le passe-partout inutile n'est pas une douleur.
Michael Shaw
2
@hyde: Mais la douleur n'est pas supprimée. Le passe-partout inutile est toujours là, encombrant le code sans raison. S'il y a une raison pour le passe-partout, quelle est-elle?
Michael Shaw
2
@MichaelShaw Si l'exception est inutile, supprimez-la: ignorez la situation ou renvoyez la valeur d'erreur à la place. S'il s'agit d'un bug ou d'une situation irrécupérable: utilisez une exception non vérifiée. Ce qui reste est aussi important que, par exemple, les types de paramètres, pas un passe-partout inutile. S'il s'agit d'une mauvaise API dans la bibliothèque existante, envisagez la méthode / classe wrapper, l'utilisation d'une autre bibliothèque ou tout simplement la mauvaise API.
hyde
1

car avec Maybevous, vous pouvez retarder la gestion de l'erreur jusqu'à ce que vous ayez réellement besoin de la valeur (qui peut être à quelques appels de méthode)

alors que l'exception vérifiée doit être gérée sur le lieu de l'appel

le seul avantage des exceptions est que plus d'informations peuvent être transmises sur les raisons de l'échec (sauf si quelqu'un développe un MaybeErroravec un champ jetable quand c'est une erreur)

monstre à cliquet
la source
2
Mais je peux différer le traitement de l'exception vérifiée en déclarant que ma méthode lève cette exception.
Mad Scientist
1
@MadScientist qui ne monte que la pile des appels, alors que peut-être peut aller dans toutes les directions
cliquetis monstre
5
Je pense que vous ne devez pas confondre les Maybetypes avec les erreurs de gestion. Une exception est utilisée pour signaler une erreur, un type d'option est utilisé pour représenter le résultat d'une fonction partielle. Une fonction partielle renvoyant Nothingn'est pas une erreur.
Giorgio
@MadScientist: Si un appel de méthode renvoie une indication "Valeur non valide", l'instruction immédiatement après son exécution peut être exécutée. En revanche, si une méthode lève une exception qui n'est pas immédiatement interceptée, l'instruction suivant l'appel sera ignorée. Laisser les exceptions vérifiées s'infiltrer dans la pile des appels est généralement mauvais (et cela n'aurait pas dû être le moyen le plus simple de les traiter) car il n'y a aucun moyen pour un appelant de dire si la condition a le sens attendu par la méthode qu'elle a appelée, ou s'il s'agit d'une condition inattendue que la méthode appelée laisse bouillonner.
supercat