Either: essenza, utilizzo e principio di funzionamento

Autore: IT Sectr Pubblicato: 2026-05-26 Tempo di lettura: 8 min

Either è un tipo funzionale che rappresenta un valore di una delle due varianti possibili: Left per gli errori e Right per il successo. A differenza delle eccezioni, Either rende la gestione degli errori esplicita a livello di tipi e non richiede blocchi try-catch. Secondo Arrow, 2026, Either è ampiamente utilizzato nei progetti Kotlin per comporre operazioni che possono fallire, senza effetti collaterali.

Punti chiave

  • Either è un tipo di dato algebrico per rappresentare due varianti mutuamente esclusive: Left (errore) e Right (successo).
  • Left tradizionalmente contiene le informazioni sull'errore, Right contiene il valore corretto.
  • Tipizzazione esplicita — Either obbliga a gestire entrambe le varianti in fase di compilazione, eliminando i guasti imprevisti.
  • Composizione — Either supporta map, flatMap e fold per catene di trasformazioni senza controlli annidati.
  • Differenza da Result — Either può memorizzare un tipo di errore arbitrario, non solo Error o Throwable.

Cos'è Either?

Either è un tipo di dato algebrico, preso in prestito dalla programmazione funzionale, che rappresenta esattamente uno di due possibili tipi. Nel contesto della gestione degli errori, la convenzione è: il tipo Left (Left) contiene una descrizione del problema, mentre il tipo Right (Right) contiene un risultato positivo.

Il concetto di Either proviene dal linguaggio Haskell e dalla categoria di tipi Either a b, dove a è il tipo del valore sinistro e b quello del valore destro. Nello sviluppo mobile, Either ha guadagnato popolarità grazie alla libreria Arrow per Kotlin e agli approcci funzionali in Swift.

Il vantaggio principale di Either rispetto alle eccezioni è l'assenza di percorsi di esecuzione nascosti. Una funzione che restituisce Either dichiara esplicitamente nella sua firma che può fallire. Il compilatore verifica che entrambe le varianti siano gestite.

A differenza del lancio di eccezioni, Either preserva la trasparenza del flusso di dati. Chiamare una funzione che restituisce Either non richiede try-catch dal lato chiamante — è sufficiente il pattern-matching o fold. Questo è particolarmente importante nelle architetture con approccio reattivo, dove ogni fonte di dati restituisce Either e le catene di trasformazione vengono costruite tramite map e flatMap.

Come funziona Either: struttura Left e Right

Either è composto da due sottotipi: Left e Right. Un'istanza di Either può essere solo uno di essi in ogni momento. La firma tipica in Kotlin è Either<E, A>, dove E è il tipo di errore e A è il tipo di valore di successo.

Tipo Left: contenitore di errore

Left rappresenta il caso di fallimento. A differenza delle eccezioni, Left non interrompe il flusso di esecuzione — restituisce semplicemente un valore che deve essere gestito. Il tipo di errore può essere qualsiasi cosa: String, Int, una classe sealed personalizzata o un modello di dominio.

Tipo Right: contenitore di successo

Right contiene il risultato corretto dell'operazione. Il nome riflette la correttezza — per convenzione, Right significa successo. Le trasformazioni come map e flatMap vengono applicate su Right, consentendo catene di calcoli senza verificare ogni passaggio.

Composizione di Either con flatMap

flatMap è il meccanismo principale di composizione di Either. Se il valore corrente è Right, flatMap applica la funzione passata e restituisce un nuovo Either. Se è Left, flatMap salta la trasformazione e propaga l'errore. Questo comportamento è chiamato valutazione a cortocircuito.

Oltre a flatMap, Either supporta mapLeft per la trasformazione dell'errore, fold per gestire entrambe le varianti in un unico posto e getOrElse per estrarre un valore con un valore predefinito. Queste funzioni coprono tutti gli scenari: dalla semplice estrazione alla composizione complessa con chiamate asincrone in coroutine Kotlin o Combine in Swift.

kotlin
fun parseInt(input: String): Either<String, Int> =
    input.toIntOrNull()?.let { Right(it) }
    ?: Left("Impossibile convertire: $input")

fun divide(a: Int, b: Int): Either<String, Int> =
    if (b == 0) Left("Divisione per zero")
    else Right(a / b)

val result = parseInt("10")
    .flatMap { divide(it, 2) }

Either in Kotlin: applicazione pratica

Nell'ecosistema Kotlin, Either è implementato nella libreria Arrow. La libreria standard di Kotlin offre Result, ma Either offre maggiore flessibilità: tipo di errore arbitrario, composizione tramite flatMap e supporto per pattern funzionali.

Libreria Arrow e Either

Arrow è una libreria funzionale per Kotlin che aggiunge Either, Option, Validated e altri tipi. Arrow.Either è una classe sealed con due sottoclassi: ArrowCore.Left e ArrowCore.Right. La libreria fornisce anche estensioni pratiche: .getOrElse(), .fold(), .mapLeft().

Esempio: Either con una richiesta di rete

Consideriamo uno scenario reale — una richiesta di rete in un'app Android con possibili errori: assenza di rete, errore del server, risposta non valida. Either consente di combinare tutte le varianti in un unico tipo di ritorno.

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 in Swift: differenza dal Result standard

In Swift, a partire dalla versione 5.0, è disponibile il tipo integrato Result, concettualmente simile a Either ma con limitazioni: l'errore deve essere conforme al protocollo Error e il valore di successo deve essere di un singolo tipo. Either in Swift viene implementato tramite un enum con due parametri generici.

Result standard vs. Either

Result<Success, Failure> è il tipo integrato di Swift, dove Failure: Error. Either non impone vincoli sul tipo di errore, consentendo di memorizzare String, strutture personalizzate o anche più tipi di errore tramite enum annidati.

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 }

Quando usare Either nelle app mobile

Either è ottimale per scenari che richiedono una gestione degli errori esplicita e type-safe senza eccezioni. Consideriamo i principali casi d'uso nello sviluppo mobile con Kotlin e Swift.

  • Richieste di rete — ogni richiesta può restituire un errore di connessione, del server o di analisi. Either raccoglie tutte le varianti in un unico tipo.
  • Validazione dei moduli — Either con un tipo di errore personalizzato rappresenta comodamente il risultato della validazione dei campi: email o password non validi.
  • Repository di dati — Either consente di combinare risultati da diverse fonti (cache, DB, rete) con un tipo di errore unificato.
  • Interprete di comandi — se l'app analizza l'input dell'utente o i comandi, Either fornisce un modo type-safe per segnalare gli errori.

Non utilizzare Either per operazioni semplici senza effetti collaterali — un valore di ritorno normale è più affidabile e facile da leggere. Either è anche eccessivo quando il fallimento è una situazione eccezionale e non uno scenario previsto.

Either è efficace anche quando si lavora con le coroutine in Kotlin. Una funzione che restituisce Either può essere chiamata all'interno di una coroutine con gestione degli errori tramite fold o mapLeft senza bloccare il thread. Ciò è particolarmente utile nelle app Android con architettura MVVM, dove ogni repository restituisce Either e la ViewModel trasforma il risultato in UiState.

Errori comuni quando si lavora con Either

Gli sviluppatori alle prime armi con Either commettono spesso errori simili. Esaminiamo i più comuni e come evitarli.

  • Ignorare Left — chiamare .getOrElse() con un valore predefinito senza analizzare la causa dell'errore vanifica l'uso di Either. Gestisci l'errore esplicitamente.
  • Tipo di errore globale — usare String o Exception come tipo comune per tutti gli Either in un progetto riduce la sicurezza dei tipi. Crea classi sealed di dominio.
  • Either annidati — un Either dentro Right (Either<E, Either<E, A>>) complica la lettura. Usa flatMap per appiattire.
  • Miscuglio con eccezioni — una funzione restituisce Either ma internamente lancia eccezioni. Ciò contraddice l'idea della gestione esplicita degli errori.

Domande frequenti

In cosa si differenzia Either da Optional?

Optional rappresenta la presenza o l'assenza di un valore (Some/None), ma non comunica la causa dell'assenza. Either fornisce due tipi concreti — sinistro per l'errore e destro per il successo — consentendo di trasmettere il contesto del fallimento.

Si può usare Either in Java?

In Java non esiste un Either integrato, ma le librerie Vavr e functionaljava forniscono implementazioni. Nello sviluppo Android, Either di Vavr è un'alternativa popolare per uno stile funzionale con lambda.

Quando è meglio usare sealed class invece di Either?

Sealed class in Kotlin è più comoda quando ci sono più di due varianti o hanno strutture diverse. Per un risultato binario (errore/successo), Either è più compatto e fornisce combinatori funzionali pronti all'uso.

Either supporta il multithreading?

Either è immutabile e thread-safe per impostazione predefinita. In Kotlin con le coroutine, Either si combina perfettamente: flatMap funziona all'interno di un ambito di coroutine e la gestione degli errori non richiede blocchi.

Dovrei usare Either per tutte le funzioni nel progetto?

No. Either è adatto per operazioni con guasti previsti (rete, validazione, logica di business). Per getter semplici e calcoli senza effetti collaterali, un tipo normale si legge più facilmente e non aggiunge complessità inutile.

Riepilogo

  • Either è un tipo funzionale per rappresentare due varianti: Left (errore) e Right (successo), rendendo la gestione degli errori esplicita a livello di tipi.
  • Left può contenere un tipo di errore arbitrario — da String a una classe sealed di dominio, a differenza del Result standard.
  • flatMap consente la composizione di Either senza controlli annidati: l'errore si propaga automaticamente attraverso l'intera catena.
  • Arrow è la libreria principale di Either per Kotlin con supporto integrato per coroutine ed estensioni.
  • Swift utilizza il Result integrato, ma Either può essere implementato tramite un enum con due parametri generici per la massima flessibilità.
  • Usa Either per richieste di rete, validazione dei moduli e repository — scenari con errori previsti.
  • Evita tipi di errore globali, ignorare Left ed Either annidati — questo riduce i vantaggi della sicurezza dei tipi.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche