Either es un tipo funcional que representa un valor de una de dos variantes posibles: Left para errores y Right para éxito. A diferencia de las excepciones, Either hace que el manejo de errores sea explícito a nivel de tipos y no requiere bloques try-catch. Según Arrow, 2026, Either se utiliza ampliamente en proyectos Kotlin para componer operaciones que pueden fallar, sin efectos secundarios.
Puntos clave
Either es un tipo de dato algebraico, tomado de la programación funcional, que representa exactamente uno de dos tipos posibles. En el contexto del manejo de errores, la convención es: el tipo Left (Left) contiene una descripción del problema, mientras que el tipo Right (Right) contiene un resultado exitoso.
El concepto de Either proviene del lenguaje Haskell y la categoría de tipos Either a b, donde a es el tipo del valor izquierdo y b el del derecho. En el desarrollo móvil, Either ganó popularidad gracias a la biblioteca Arrow para Kotlin y los enfoques funcionales en Swift.
La ventaja clave de Either sobre las excepciones es la ausencia de rutas de ejecución ocultas. Una función que devuelve Either declara explícitamente en su firma que puede fallar. El compilador garantiza que ambas variantes sean manejadas.
A diferencia de lanzar excepciones, Either preserva la transparencia del flujo de datos. Llamar a una función que devuelve Either no requiere try-catch del lado del llamante — basta con pattern-matching o fold. Esto es especialmente importante en arquitecturas con enfoque reactivo, donde cada fuente de datos devuelve Either y las cadenas de transformación se construyen con map y flatMap.
Either consta de dos subtipos: Left y Right. Una instancia de Either solo puede ser uno de ellos en cada momento. La firma típica en Kotlin es Either<E, A>, donde E es el tipo de error y A el tipo de valor exitoso.
Left representa el caso de fallo. A diferencia de las excepciones, Left no interrumpe el flujo de ejecución — simplemente devuelve un valor que debe ser manejado. El tipo de error puede ser cualquiera: String, Int, una clase sellada personalizada o un modelo de dominio.
Right contiene el resultado correcto de la operación. El nombre refleja la corrección — por convención, Right significa éxito. Las transformaciones map y flatMap se aplican sobre Right, permitiendo cadenas de cálculos sin verificar cada paso.
flatMap es el mecanismo principal de composición de Either. Si el valor actual es Right, flatMap aplica la función recibida y devuelve un nuevo Either. Si es Left, flatMap omite la transformación y propaga el error. Este comportamiento se denomina evaluación de cortocircuito.
Además de flatMap, Either admite mapLeft para transformar el error, fold para manejar ambas variantes en un solo lugar y getOrElse para extraer un valor con un valor predeterminado. Estas funciones cubren todos los escenarios: desde la extracción simple hasta la composición compleja con llamadas asíncronas en corrutinas de Kotlin o Combine en Swift.
fun parseInt(input: String): Either<String, Int> =
input.toIntOrNull()?.let { Right(it) }
?: Left("No se pudo convertir: $input")
fun divide(a: Int, b: Int): Either<String, Int> =
if (b == 0) Left("División por cero")
else Right(a / b)
val result = parseInt("10")
.flatMap { divide(it, 2) }
En el ecosistema Kotlin, Either está implementado en la biblioteca Arrow. La biblioteca estándar de Kotlin ofrece Result, pero Either proporciona más flexibilidad: tipo de error arbitrario, composición mediante flatMap y soporte para patrones funcionales.
Arrow es una biblioteca funcional para Kotlin que añade Either, Option, Validated y otros tipos. Arrow.Either es una clase sellada con dos subclases: ArrowCore.Left y ArrowCore.Right. La biblioteca también proporciona extensiones convenientes: .getOrElse(), .fold(), .mapLeft().
Consideremos un escenario real — una petición de red en una aplicación Android con posibles errores: falta de red, error del servidor, respuesta incorrecta. Either permite combinar todas las variantes en un único tipo de retorno.
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, a partir de la versión 5.0, está disponible el tipo integrado Result, conceptualmente similar a Either pero con limitaciones: el error debe cumplir el protocolo Error y el valor de éxito debe ser de un único tipo. Either en Swift se implementa mediante un enum con dos parámetros genéricos.
Result<Success, Failure> es el tipo integrado de Swift, donde Failure: Error. Either no impone restricciones sobre el tipo de error, lo que permite almacenar String, estructuras personalizadas o incluso múltiples tipos de error mediante enums anidados.
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 es óptimo para escenarios que requieren manejo de errores explícito y type-safe sin excepciones. Consideremos los casos principales de uso en desarrollo móvil con Kotlin y Swift.
No uses Either para operaciones simples sin efectos secundarios — un valor de retorno normal es más fiable y fácil de leer. Either también es excesivo cuando el fallo es una situación excepcional y no un escenario esperado.
Either también es eficaz al trabajar con corrutinas en Kotlin. Una función que devuelve Either puede llamarse dentro de una corrutina con manejo de errores mediante fold o mapLeft sin bloquear el hilo. Esto es especialmente útil en aplicaciones Android con arquitectura MVVM, donde cada repositorio devuelve Either y la ViewModel transforma el resultado en UiState.
Los desarrolladores que se familiarizan por primera vez con Either suelen cometer errores similares. Examinemos los más comunes y cómo evitarlos.
Preguntas frecuentes
Optional representa la presencia o ausencia de un valor (Some/None), pero no informa la causa de la ausencia. Either proporciona dos tipos concretos — izquierdo para error y derecho para éxito — lo que permite transmitir el contexto del fallo.
En Java no hay Either incorporado, pero las bibliotecas Vavr y functionaljava proporcionan implementaciones. En desarrollo Android, Either de Vavr es una alternativa popular para un estilo funcional con lambdas.
Sealed class en Kotlin es más conveniente cuando hay más de dos variantes o tienen estructuras diferentes. Para un resultado binario (error/éxito), Either es más compacto y proporciona combinadores funcionales listos para usar.
Either es inmutable y seguro para hilos por defecto. En Kotlin con corrutinas, Either se combina perfectamente: flatMap funciona dentro de un ámbito de corrutina y el manejo de errores no requiere bloqueos.
No. Either es adecuado para operaciones con fallos esperados (red, validación, lógica de negocio). Para getters simples y cálculos sin efectos secundarios, un tipo normal se lee más fácilmente y no añade complejidad innecesaria.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también