Either est un type fonctionnel qui représente une valeur parmi deux variantes possibles : Left pour les erreurs et Right pour le succès. Contrairement aux exceptions, Either rend la gestion d'erreurs explicite au niveau des types et ne nécessite pas de blocs try-catch. Selon Arrow, 2026, Either est largement utilisé dans les projets Kotlin pour composer des opérations susceptibles d'échouer, sans effets secondaires.
Points clés
Either est un type de données algébrique, emprunté à la programmation fonctionnelle, qui représente exactement un de deux types possibles. Dans le contexte de la gestion d'erreurs, la convention est la suivante : le type Left (Left) contient une description du problème, tandis que le type Right (Right) contient un résultat réussi.
Le concept d'Either provient du langage Haskell et de la catégorie de types Either a b, où a est le type de la valeur gauche et b celui de la valeur droite. Dans le développement mobile, Either a gagné en popularité grâce à la bibliothèque Arrow pour Kotlin et aux approches fonctionnelles en Swift.
L'avantage clé d'Either par rapport aux exceptions est l'absence de chemins d'exécution cachés. Une fonction qui retourne Either déclare explicitement dans sa signature qu'elle peut échouer. Le compilateur vérifie que les deux variantes sont traitées.
Contrairement au lancement d'exceptions, Either préserve la transparence du flux de données. Appeler une fonction qui retourne Either ne nécessite pas de try-catch du côté de l'appelant — le pattern-matching ou fold suffit. Ceci est particulièrement important dans les architectures à approche réactive, où chaque source de données retourne Either et les chaînes de transformation sont construites via map et flatMap.
Either se compose de deux sous-types : Left et Right. Une instance d'Either ne peut être que l'un d'eux à tout moment. La signature typique en Kotlin est Either<E, A>, où E est le type d'erreur et A le type de valeur de succès.
Left représente le cas d'échec. Contrairement aux exceptions, Left n'interrompt pas le flux d'exécution — il retourne simplement une valeur qui doit être traitée. Le type d'erreur peut être n'importe quoi : String, Int, une classe sealed personnalisée ou un modèle domaine.
Right contient le résultat correct de l'opération. Le nom reflète la correction — par convention, Right signifie succès. Les transformations comme map et flatMap sont appliquées sur Right, permettant des chaînes de calcul sans vérifier chaque étape.
flatMap est le mécanisme principal de composition d'Either. Si la valeur actuelle est Right, flatMap applique la fonction passée et retourne un nouvel Either. Si c'est Left, flatMap ignore la transformation et propage l'erreur. Ce comportement est appelé évaluation de court-circuit.
En plus de flatMap, Either prend en charge mapLeft pour la transformation d'erreur, fold pour traiter les deux variantes en un seul endroit et getOrElse pour extraire une valeur avec une valeur par défaut. Ces fonctions couvrent tous les scénarios : de l'extraction simple à la composition complexe avec des appels asynchrones dans les coroutines Kotlin ou Combine en Swift.
fun parseInt(input: String): Either<String, Int> =
input.toIntOrNull()?.let { Right(it) }
?: Left("Échec de la conversion : $input")
fun divide(a: Int, b: Int): Either<String, Int> =
if (b == 0) Left("Division par zéro")
else Right(a / b)
val result = parseInt("10")
.flatMap { divide(it, 2) }
Dans l'écosystème Kotlin, Either est implémenté dans la bibliothèque Arrow. La bibliothèque standard de Kotlin propose Result, mais Either offre plus de flexibilité : type d'erreur arbitraire, composition via flatMap et prise en charge des motifs fonctionnels.
Arrow est une bibliothèque fonctionnelle pour Kotlin qui ajoute Either, Option, Validated et d'autres types. Arrow.Either est une classe sealed avec deux sous-classes : ArrowCore.Left et ArrowCore.Right. La bibliothèque fournit également des extensions pratiques : .getOrElse(), .fold(), .mapLeft().
Considérons un scénario réel — une requête réseau dans une application Android avec des erreurs possibles : absence de réseau, erreur serveur, réponse invalide. Either permet de combiner toutes les variantes en un seul type de retour.
sealed class NetworkError {
data class NoConnection(val message: String): NetworkError()
data class ServerError(val code: Int): NetworkError()
data class ParseError(val detail: String): NetworkError()
}
suspend fun fetchUser(id: String): Either<NetworkError, User> {
return try {
val response = api.getUser(id)
if (response.isSuccessful) {
Right(response.body()!!)
} else {
Left(NetworkError.ServerError(response.code()))
}
} catch (e: IOException) {
Left(NetworkError.NoConnection(e.message ?: ""))
}
}
En Swift, à partir de la version 5.0, le type intégré Result est disponible, conceptuellement similaire à Either mais avec des limitations : l'erreur doit être conforme au protocole Error et la valeur de succès doit être d'un seul type. Either en Swift est implémenté via une enum avec deux paramètres génériques.
Result<Success, Failure> est le type intégré de Swift, où Failure: Error. Either n'impose pas de contraintes sur le type d'erreur, permettant de stocker des String, des structures personnalisées ou même plusieurs types d'erreur via des enums imbriquées.
enum Either<E, A> {
case left(E)
case right(A)
func map<B>(_ transform: (A) -> B) -> Either<E, B> {
switch self {
case .left(let e): return .left(e)
case .right(let a): return .right(transform(a))
}
}
}
let result: Either<String, Int> = .right(42)
let mapped = result.map { $0 * 2 }
Either est optimal pour les scénarios nécessitant une gestion d'erreurs explicite et type-safe sans exceptions. Examinons les principaux cas d'utilisation dans le développement mobile avec Kotlin et Swift.
N'utilisez pas Either pour des opérations simples sans effets secondaires — une valeur de retour normale est plus fiable et plus facile à lire. Either est également excessif lorsque l'échec est une situation exceptionnelle et non un scénario attendu.
Either est également efficace lorsqu'on travaille avec des coroutines en Kotlin. Une fonction qui retourne Either peut être appelée dans une coroutine avec une gestion d'erreurs via fold ou mapLeft sans bloquer le fil d'exécution. Ceci est particulièrement utile dans les applications Android avec une architecture MVVM, où chaque référentiel retourne Either et le ViewModel transforme le résultat en UiState.
Les développeurs qui découvrent Either commettent souvent des erreurs similaires. Examinons les plus courantes et comment les éviter.
Foire aux questions
Optional représente la présence ou l'absence d'une valeur (Some/None), mais n'indique pas la cause de l'absence. Either fournit deux types concrets — gauche pour l'erreur et droit pour le succès — permettant de transmettre le contexte de l'échec.
En Java, il n'y a pas d'Either intégré, mais les bibliothèques Vavr et functionaljava fournissent des implémentations. Dans le développement Android, Either de Vavr est une alternative populaire pour un style fonctionnel avec des lambdas.
Sealed class en Kotlin est plus pratique lorsqu'il y a plus de deux variantes ou qu'elles ont des structures différentes. Pour un résultat binaire (erreur/succès), Either est plus compact et fournit des combinateurs fonctionnels prêts à l'emploi.
Either est immuable et thread-safe par défaut. En Kotlin avec les coroutines, Either se combine parfaitement : flatMap fonctionne dans un scope de coroutine et la gestion d'erreurs ne nécessite pas de verrous.
Non. Either convient aux opérations avec des échecs attendus (réseau, validation, logique métier). Pour les getters simples et les calculs sans effets secondaires, un type normal se lit plus facilement et n'ajoute pas de complexité inutile.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi