Either — un tip funcțional care reprezintă valoarea uneia dintre cele două variante posibile: stânga (Left) pentru eroare și dreapta (Right) pentru succes. Spre deosebire de excepții, Either face gestionarea erorilor explicită la nivel de tipuri și nu necesită blocuri try-catch. Conform datelor Arrow, 2026, Either este utilizat pe scară largă în proiectele Kotlin pentru compunerea operațiilor care pot eșua, fără efecte secundare.
Principalele
Either — este un tip de date algebric împrumutat din programarea funcțională, care reprezintă valoarea exact a unuia dintre cele două tipuri posibile. În contextul gestionării erorilor, convenția este: tipul stâng (Left) conține descrierea problemei, iar dreapta (Right) — rezultatul reușit.
Conceptul Either provine din limbajul Haskell și categoria tipurilor Either a b, unde a este tipul valorii stângi, b — a celei drepte. În dezvoltarea mobilă, Either a câștigat popularitate datorită bibliotecii Arrow pentru Kotlin și abordărilor funcționale în Swift.
Avantajul cheie al Either față de excepții — absența căilor de execuție ascunse. O funcție care returnează Either declară explicit în semnătura sa că se poate încheia cu eroare. Compilatorul controlează dacă ambele variante au fost gestionate.
Spre deosebire de aruncarea excepțiilor, Either păstrează transparența fluxului de date. Apelarea unei funcții care returnează Either nu necesită try-catch în partea codului apelant — este suficient pattern-matching sau fold. Acest lucru este deosebit de important în arhitecturile cu abordare reactivă, unde fiecare sursă de date returnează Either, iar lanțul de transformări se construiește prin map și flatMap.
Either este format din două subtipuri: Left și Right. O instanță Either poate fi doar una dintre ele în fiecare moment. Semnătura tipică în Kotlin arată ca Either<E, A>, unde E este tipul erorii, A — tipul valorii de succes.
Left reprezintă cazul defecțiunii. Spre deosebire de excepții, Left nu întrerupe fluxul de execuție — pur și simplu returnează o valoare care trebuie gestionată. Tipul erorii poate fi orice: String, Int, sealed class personalizat sau model de domeniu.
Right conține rezultatul corect al operației. Numele reflectă „corectitudinea" — prin convenție Right înseamnă succes. Pe Right se aplică transformările map și flatMap, ceea ce permite construirea lanțurilor de calcule fără verificarea fiecărui pas.
flatMap — mecanismul principal de compunere a Either. Dacă valoarea curentă este Right, flatMap aplică funcția transmisă și returnează un nou Either. Dacă este Left — flatMap omite transformarea și transmite eroarea mai departe. Acest comportament se numește short-circuit evaluation.
Pe lângă flatMap, Either suportă mapLeft pentru transformarea erorii, fold pentru gestionarea ambelor variante într-un singur loc și getOrElse pentru extragerea valorii cu o valoare implicită. Aceste funcții acoperă toate scenariile: de la extragerea simplă până la compunerea complexă cu apeluri asincrone în corutinele Kotlin sau Combine în Swift.
fun parseInt(input: String): Either<String, Int> =
input.toIntOrNull()?.let { Right(it) }
?: Left("Nu s-a putut converti: $input")
fun divide(a: Int, b: Int): Either<String, Int> =
if (b == 0) Left("Împărțire la zero")
else Right(a / b)
val result = parseInt("10")
.flatMap { divide(it, 2) }
În ecosistemul Kotlin Either este implementat în biblioteca Arrow. Biblioteca standard Kotlin oferă Result, dar Either oferă mai multă flexibilitate: tip de eroare arbitrar, compunere prin flatMap și suport pentru modele funcționale.
Arrow — bibliotecă funcțională pentru Kotlin care adaugă Either, Option, Validated și alte tipuri. Arrow.Either — sealed class cu doi moștenitori: ArrowCore.Left și ArrowCore.Right. Biblioteca oferă și extensii pentru lucru confortabil: .getOrElse(), .fold(), .mapLeft().
Să analizăm un scenariu real — o cerere de rețea într-o aplicație Android cu erori posibile: lipsa rețelei, eroare server, răspuns incorect. Either permite combinarea tuturor variantelor într-un singur tip returnat.
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 ?: ""))
}
}
În Swift începând cu versiunea 5.0 a apărut tipul încorporat Result, care este conceptual similar cu Either, dar are limitări: eroarea trebuie să corespundă protocolului Error, iar valoarea de succes — unui singur tip. Either în Swift se implementează prin enum cu doi parametri generici.
Result<Success, Failure> — tipul încorporat Swift, unde Failure: Error. Either nu impune restricții asupra tipului de eroare, ceea ce permite stocarea unui String, a unor structuri personalizate sau chiar a mai multor tipuri de erori prin enum-uri imbricate.
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 este optim pentru scenariile care necesită gestionarea explicită și tip-securizată a erorilor fără excepții. Să analizăm principalele cazuri de utilizare în dezvoltarea mobilă în Kotlin și Swift.
Nu folosiți Either pentru operații simple fără efecte secundare — o valoare returnată obișnuită este mai fiabilă și mai ușor de citit. Either este, de asemenea, redundant când defecțiunea este o situație excepțională, nu un scenariu așteptat.
Either este eficient și la lucrul cu corutinele în Kotlin. O funcție care returnează Either poate fi apelată în interiorul unei corutine cu gestionarea erorii prin fold sau mapLeft fără blocarea firului de execuție. Acest lucru este deosebit de util în aplicațiile Android cu arhitectura MVVM, unde fiecare repozitoriu returnează Either, iar ViewModel transformă rezultatul în UiState.
Dezvoltatorii care se familiarizează pentru prima dată cu Either fac adesea greșeli similare. Să analizăm cele mai frecvente și modalitățile de a le evita.
Întrebări frecvente
Optional reprezintă prezența sau absența valorii (Some/None), dar nu comunică cauza absenței. Either oferă două tipuri concrete — stânga pentru eroare și dreapta pentru succes, ceea ce permite transmiterea contextului defecțiunii.
În Java nu există Either încorporat, dar bibliotecile Vavr și functionaljava oferă implementare. În dezvoltarea Android, Either din Vavr este o alternativă populară pentru stilul funcțional cu lambde.
Sealed class în Kotlin este mai comod când variantele sunt mai mult de două sau au structură diferită. Pentru un rezultat binar (eroare/succes) Either este mai compact și oferă combinatori funcționali gata pregătiți.
Either este imutabil și sigur pentru fire de execuție implicit. În Kotlin cu corutine, Either se combină excelent: flatMap funcționează în interiorul coroutine scope, iar gestionarea erorilor nu necesită blocări.
Nu. Either este potrivit pentru operații cu defecțiuni așteptate (rețea, validare, logică de afaceri). Pentru gettere simple și calcule fără efecte secundare, tipul obișnuit este mai ușor de citit și nu adaugă complexitate inutilă.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și