Either: esența, aplicarea și principiul de funcționare

Autor: IT Sectr Publicat: 2026-05-26 Timp de citire: 8 min

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 — un tip de date algebric pentru reprezentarea a două variante care se exclud reciproc: Left (eroare) și Right (succes).
  • Left conține în mod tradițional informații despre eroare, Right — valoarea corectă.
  • Tipizare explicită — Either forțează gestionarea ambelor variante în faza de compilare, eliminând defecțiunile neașteptate.
  • Compunere — Either suportă map, flatMap și fold pentru lanțuri de transformări fără verificări imbricate.
  • Diferența față de Result — Either poate stoca un tip de eroare arbitrar, nu doar Error sau Throwable.

Ce este Either?

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.

Cum funcționează Either: structura Left și Right

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.

Tipul Left: container de eroare

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.

Tipul Right: container de succes

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.

Compunerea Either prin flatMap

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.

kotlin
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) }

Either în Kotlin: aplicare practică

Î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.

Biblioteca Arrow și Either

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().

Exemplu: Either cu cerere de rețea

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.

kotlin
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 ?: ""))
    }
}

Either în Swift: diferența față de Result standard

Î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 standard versus Either

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.

swift
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 }

Când să folosim Either în aplicațiile mobile

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.

  • Cereri de rețea — fiecare cerere poate returna o eroare de conexiune, server sau parsare. Either colectează toate variantele într-un singur tip.
  • Validare formulare — Either cu un tip de eroare personalizat reprezintă convenabil rezultatul verificării câmpurilor de intrare: email sau parolă invalidă.
  • Repozitoriu de date — Either permite combinarea rezultatului din diferite surse (cache, bază de date, rețea) cu un tip de eroare unitar.
  • Interpretor de comenzi — dacă aplicația analizează intrarea utilizatorului sau comenzile, Either oferă o modalitate tip-securizată de a raporta eroarea.

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.

Greșeli tipice la lucrul cu Either

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.

  • Ignorarea Left — apelarea .getOrElse() cu o valoare implicită fără a analiza cauza erorii lipsește de sens utilizarea Either. Gestionați eroarea explicit.
  • Tip global de eroare — utilizarea String sau Exception ca tip comun pentru toate Either-urile din proiect reduce siguranța tipurilor. Creați sealed class-uri de domeniu.
  • Either-uri imbricate — Either repetat în interiorul Right (Either<E, Either<E, A>>) complică citirea. Folosiți flatMap pentru aplatizare.
  • Amestecarea cu excepții — funcția returnează Either, dar în interior aruncă o excepție. Aceasta contrazice ideea de gestionare explicită a erorilor.

Întrebări frecvente

Cu ce se deosebește Either de Optional?

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.

Se poate folosi Either în Java?

Î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.

Când să folosim sealed class în loc de Either?

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.

Suportă Either multi-threading-ul?

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.

Merită să folosim Either pentru toate funcțiile din proiect?

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

  • Either — tip funcțional pentru reprezentarea a două variante: Left (eroare) și Right (succes), făcând gestionarea defecțiunilor explicită la nivel de tipuri.
  • Left poate conține orice tip de eroare — de la String la sealed class de domeniu, spre deosebire de Result standard.
  • flatMap asigură compunerea Either fără verificări imbricate: eroarea se propagă automat prin întregul lanț.
  • Arrow — biblioteca principală Either pentru Kotlin cu suport încorporat pentru corutine și extensii.
  • Swift folosește Result încorporat, dar Either se implementează prin enum cu doi parametri generici pentru flexibilitate maximă.
  • Aplicați Either pentru cereri de rețea, validare formulare și repozitorii — scenarii cu erori așteptate.
  • Evitați tipul global de eroare, ignorarea Left și Either-urile imbricate — acestea reduc avantajele siguranței tipurilor.

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.

Discutați proiectul

Citiți și