Introduction à la gestion d’erreurs en programmation fonctionnelle. Partie 1 : Scala

Chez Kaizen nous aimons le sentiment de sécurité que procure la programmation fonctionnelle.
Un des premiers bénéfices que l’on peut observer dans ce type de programmation est la facilité avec laquelle on peut traiter les erreurs.

La programmation fonctionnelle typée se démarque sur ce sujet de deux manières :

  • en reposant sur des fonctions et des types de retour fiables
  • en utilisant des types facilitant la composition

Par exemple, cette méthode a un type de retour que l’on peut considérer comme « non fiable » :

La signature nous indique que l’on va récupérer une valeur de type String, mais la méthode peut retourner une référence nulle ou encore ne rien retourner du tout en lançant une exception.

Voyons maintenant comment adresser cette problématique à l’aide de la programmation fonctionnelle. Nous utiliserons le langage Scala dans les exemples qui suivent. Le type Option permet d’éviter de recourir à des références nulles. Option[T] signifie qu’on peut avoir une valeur de type T ou une absence valeur. Option[T] peut prendre deux valeurs : Some[T] si la valeur est présente et None dans le cas contraire.

Exemple de fonction renvoyant une option :

Le type Option propose plusieurs opérations intéressantes, comme map, flatMap ou getOrElse.

L’opération map permet de modifier le résultat d’une option, dans le cas où cette option est définie (de type Some). Dans le cas contraire rien ne se produit et on évite les null pointer exceptions. Voici comment on peut implémenter la méthode findName à l’aide de Option et map :

La méthode flatMap permet de combiner deux options (voir plus bas dans ce post). La méthode getOrElse permet de récupérer la valeur encapsulée en fournissant une valeur par défaut en cas de None :

On peut également utiliser du pattern matching, c’est à dire préciser le comportement à adopter en fonction des différents cas :

Si l’on souhaite avoir plus de détails sur la cause d’une erreur, on peut utiliser le type Either à la place d’Option. Either[L, R] peut prendre deux valeurs : Left[L] ou Right[R]. Le type Left est utilisé pour contenir les erreurs, le type Right pour les résultats dont le calcul a réussi. On peut adapter l’exemple précédent avec Either :

Comme pour Option, map sera appelé uniquement si le traitement a réussi (type Right), si person est de type Left, findName renverra directement ce Left, qui contiendra dans notre cas une valeur de type String représentant l’erreur rencontrée.

On peut également utiliser le pattern matching avec Either :

Combiner des résultats

Lorsque l’on a plusieurs résultats de type Option ou plusieurs Either et qu’on veut les combiner pour obtenir un résultat global, on peut utiliser la composition grâce à la méthode flatMap :

On peut aussi simplifier le code de cette manière :

Le résultat de giveOption(1) est envoyé dans la fonction giveOption2.

Il existe une syntaxe en Scala appelée « for comprehension » qui permet de combiner ce type de wrapper, c’est à dire les types comportant entre autres choses une méthode flatMap (appelés aussi monades) :

Une fois compilé, le code sera équivalent à l’exemple précédent écrit avec flatMap (on parle de sucre syntaxique).
Si les 2 options sont de type Some, leur combinaison donnera un type Some. Si une des deux options est de type None, le résultat sera None.

On peut appliquer la même recette avec Either :

Ou :

Note : lorsque l’on combine plusieurs options ou either avec flatMap (ou avec un for comprehension), le traitement s’arrête au premier None ou au premier Left rencontré.
Si on a besoin d’accumuler toutes les erreurs, par exemple dans une liste, on peut utiliser le type Validated de la librairie Cats ou d’autres librairies comme Scala Hamsters.

Résultats asynchrones

En Scala, le type Future permet de représenter le résultat d’une opération asynchrone. On peut combiner les valeurs de type Future comme nous l’avons fait avec Option et Either :

Il est également possible de combiner des valeurs de type Future[Option] ou Future[Either] à l’aide de wrappers :

Dans cet exemple le wrapper FutureEither provient de la librairie Scala Hamsters.

Tout le monde n’ayant pas la chance de pouvoir utiliser Scala dans son travail au quotidien, nous exploreronsla mise en œuvre de ces pratiques dans les langages Kotlin et Typescript dans la prochaine partie de ce post.

1 réaction sur “ Introduction à la gestion d’erreurs en programmation fonctionnelle. Partie 1 : Scala ”

  1. Ping Introduction à la gestion d’erreurs en programmation fonctionnelle. Partie 2 : Kotlin et TypeScript – KZSLAB : Kaizen Solutions

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.