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 για εξαγωγή τιμής με προεπιλογή. Αυτές οι συναρτήσεις καλύπτουν όλα τα σενάρια: από απλή εξαγωγή έως σύνθετη σύνθεση με ασύγχρονες κλήσεις σε coroutine 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 είναι επίσης αποτελεσματικό κατά την εργασία με coroutine στην Kotlin. Μια συνάρτηση που επιστρέφει Either μπορεί να κληθεί μέσα σε ένα coroutine με χειρισμό σφάλματος μέσω 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 με coroutine, το Either συνδυάζεται άψογα: το flatMap λειτουργεί μέσα στο coroutine scope και ο χειρισμός σφαλμάτων δεν απαιτεί κλειδώματα.
Όχι. Either είναι κατάλληλο για λειτουργίες με αναμενόμενες αποτυχίες (δίκτυο, επικύρωση, επιχειρηματική λογική). Για απλές λήψεις και υπολογισμούς χωρίς παρενέργειες, ο συνηθισμένος τύπος είναι πιο ευανάγνωστος και δεν προσθέτει περιττή πολυπλοκότητα.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης