Either — функционални тип који представља вредност једне од две могуће варијанте: лева (Left) за грешку и десна (Right) за успех. За разлику од изузетака, Either чини обраду грешака експлицитном на нивоу типова и не захтева блокове try-catch. Према подацима Arrow, 2026, Either се широко примењује у Kotlin пројектима за композицију операција које могу да заврше неуспехом, без споредних ефеката.
Главно
Either — је алгебарски тип података позајмљен из функционалног програмирања, који представља вредност тачно једног од два могућа типа. У контексту обраде грешака усвојена је конвенција: леви тип (Left) садржи опис проблема, а десни (Right) — успешан резултат.
Концепт Either потиче из језика Haskell и категорије типова Either a b, где a представља тип леве вредности, b — десне. У мобилном развоју, Either је стекао популарност захваљујући библиотеци Arrow за Kotlin и функционалним приступима у Swift.
Кључна предност Either над изузецима — одсуство скривених путања извршења. Функција која враћа Either експлицитно изјављује у свом потпису да може да се заврши грешком. Компилатор контролише да ли су обе варијанте обрађене.
За разлику од бацања изузетака, Either чува транспарентност тока података. Позив функције која враћа Either не захтева try-catch на страни позивајућег кода — довољан је pattern-matching или fold. Ово је посебно важно у архитектурама са реактивним приступом, где сваки извор података враћа Either, а ланац трансформација се гради кроз map и flatMap.
Either се састоји од два подтипа: Left и Right. Инстанца Either може бити само једна од њих у сваком тренутку. Типичан потпис у Kotlin изгледа као Either<E, A>, где E представља тип грешке, A — тип успешне вредности.
Left представља случај отказа. За разлику од изузетака, Left не прекида ток извршења — једноставно враћа вредност коју треба обрадити. Тип грешке може бити било који: String, Int, прилагођени sealed class или доменски модел.
Right садржи исправан резултат операције. Назив одражава „исправност" — по конвенцији Right значи успех. Управо на Right се примењују трансформације map и flatMap, што омогућава градњу ланаца прорачуна без провере сваког корака.
flatMap — главни механизам композиције Either. Ако је тренутна вредност Right, flatMap примењује прослеђену функцију и враћа нови Either. Ако је Left — flatMap прескаче трансформацију и прослеђује грешку даље. Ово понашање се назива short-circuit evaluation.
Поред flatMap, Either подржава mapLeft за трансформацију грешке, fold за обраду обе варијанте на једном месту и getOrElse за издвајање вредности са подразумеваном. Ове функције покривају све сценарије: од једноставног издвајања до сложене композиције са асинхроним позивима у корутинама Kotlin или Combine у Swift.
fun parseInt(input: String): Either<String, Int> =
input.toIntOrNull()?.let { Right(it) }
?: Left("Није могуће конвертовати: $input")
fun divide(a: Int, b: Int): Either<String, Int> =
if (b == 0) Left("Дељење нулом")
else Right(a / b)
val result = parseInt("10")
.flatMap { divide(it, 2) }
У екосистему Kotlin Either је имплементиран у библиотеци Arrow. Стандардна библиотека Kotlin нуди Result, али Either даје више флексибилности: произвољан тип грешке, композицију кроз flatMap и подршку за функционалне обрасце.
Arrow — функционална библиотека за Kotlin која додаје Either, Option, Validated и друге типове. Arrow.Either — sealed class са два наследника: ArrowCore.Left и ArrowCore.Right. Библиотека такође пружа проширења за згодан рад: .getOrElse(), .fold(), .mapLeft().
Размотримо реалан сценарио — мрежни захтев у Android апликацији са могућим грешкама: недостатак мреже, грешка сервера, неисправан одговор. Either омогућава обједињавање свих варијанти у једном повратном типу.
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 ?: ""))
}
}
У Swift од верзије 5.0 појавио се уграђени тип Result, који је концептуално сличан Either, али има ограничења: грешка мора да одговара протоколу Error, а успешна вредност — једном типу. Either у Swift се имплементира кроз enum са два генеричка параметра.
Result<Success, Failure> — уграђени тип Swift, где Failure: Error. Either не намеће ограничења на тип грешке, што омогућава складиштење String, прилагођених структура или чак више типова грешака кроз угњеждене enum.
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 је оптималан за сценарије који захтевају експлицитну и типолошки безбедну обраду грешака без изузетака. Размотримо главне случајеве примене у мобилном развоју на Kotlin и Swift.
Немојте користити Either за једноставне операције без споредних ефеката — обична повратна вредност је поузданија и читљивија. Either је такође сувишан када је отказ изузетна ситуација, а не очекивани сценарио.
Either је такође ефикасан при раду са корутинама у Kotlin. Функција која враћа Either може бити позвана унутар корутине са обрадом грешке кроз fold или mapLeft без блокирања нити. Ово је посебно корисно у Android апликацијама са MVVM архитектуром, где сваки репозиторијум враћа Either, а ViewModel трансформише резултат у UiState.
Програмери који се први пут сусрећу са Either често праве сличне грешке. Размотримо најчешће и начине да их избегнемо.
Често постављана питања
Optional представља присуство или одсуство вредности (Some/None), али не саопштава узрок одсуства. Either даје два конкретна типа — леви за грешку и десни за успех, што омогућава преношење контекста отказа.
У Java не постоји уграђени Either, али библиотеке Vavr и functionaljava пружају имплементацију. У Android развоју, Either из Vavr је популарна алтернатива за функционални стил са ламбда изразима.
Sealed class у Kotlin је згоднији када варијанти има више од две или имају различиту структуру. За бинарни исход (грешка/успех) Either је компактнији и пружа готове функционалне комбинаторе.
Either је имутабилан и безбедан за нити подразумевано. У Kotlin са корутинама Either се одлично комбинује: flatMap ради унутар coroutine scope, а обрада грешака не захтева блокаде.
Не. Either је прикладан за операције са очекиваним отказима (мрежа, валидација, пословна логика). За једноставне гетере и прорачуне без споредних ефеката обичан тип је читљивији и не додаје непотребну сложеност.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође