Moritz Lindner
06/01/2022, 8:29 PMEither<A, Option<B>
and want to create a Either<A, B>
. If the Option is None
the Either should be Left<A>
and if it is Some
I want the Either to be Right<B>
.
I did not find a function in the library and since MonadeTransformers are not an option I came up with the following solution:
fun <A, B> Either<A, Option<B>>.unwrapOptionOrElse(other: () -> A): Either<A, B> {
return flatMap { option -> option.fold({ other().left() }, { it.right() }) }
}
Is this a reasonable way of handling this case or should I change something?
Regards Moritz 🙂raulraja
06/01/2022, 9:18 PMEither<A, Option<B>>
in application code is often times a sign there is too much indirection and wrapping that could potentially be resolved in a different way. do you have an example on where this function is useful ?Moritz Lindner
06/01/2022, 9:30 PMEither<A, Option<B>
for a typical findById
Function.
We choose this approach because we currently don't use a restricted hierarchy for the left case.
(We basically have just something like this:
class Error(
val errorMessage: String,
val errorCode: ErrorCode,
val httpStatusCode: Int,
val errorUid: UUID,
throwable: Throwable? = null
) {
/// ...
}
We could use this Error
to describe the typical "No Element by this id" but we choose to encode this as a Option<B>
Right
case.Moritz Lindner
06/01/2022, 9:32 PMprivate fun getBetriebsstelle(command: CreateStoerungsmeldungCommand): Either<Error, Betriebsstelle> {
return loadBetriebsstelle.loadByRil100(command.stoerungsOrtId)
.unwrapOptionOrElse { buildErrorFromErrorCode(KodiErrorCode.API_2002) }
}
Moritz Lindner
06/01/2022, 9:35 PMgetBetriebsstelle
function in an either forcomprehension:
return either.eager {
///...
val netzkode = getNetzKode(createStoerungsmeldungCommand).bind()
val betriebsstelle = getBetriebsstelle(createStoerungsmeldungCommand).bind()
val kodiErrorCode = checkIfStoerungsmeldungIsValid(createStoerungsmeldungCommand)
///...
}
Moritz Lindner
06/01/2022, 9:36 PMraulraja
06/01/2022, 9:39 PMMoritz Lindner
06/01/2022, 9:43 PMMoritz Lindner
06/01/2022, 9:44 PMraulraja
06/01/2022, 9:50 PMgetBetriebsstelle
and how unwrapOptionOrElse
plays a role there. For what I see in the structure of the for comprehension there may be a chance to express this function differently if you can use context receivers. @Imran/Malic also speak german natively and may be able to help better than I can.raulraja
06/01/2022, 9:53 PMImran/Malic
06/01/2022, 10:04 PMeither.eager {
///...
val netzkode = getNetzKode(createStoerungsmeldungCommand).bind()
val betriebsstelle = getBetriebsstelle(createStoerungsmeldungCommand).bind()
// val kodiErrorCode = checkIfStoerungsmeldungIsValid(createStoerungsmeldungCommand) // anstatt checkifStoerungsmeldungIsValid benutzt du ensureNotNull/ ensure von EagerEffectScope
/// .....
}
du kannst dann entweder checkifStoerungsmeldungIsValid so definieren (??? ist für Typen die ich von dem Kontext oben nicht rauslesen kann):
context(EagerEffectScope<Error>)
fun checkifStoerungsmeldungIsValid(createStoerungsmeldungCommand : ???): KodiErrorCode {
ensureNotNull(//** **//) { buildErrorFromErrorCode(KodiErrorCode.API_2002) }
// oder wenn es um Boolean Expressions geht kannst du `ensure` nutzen
// ...
return kodiErrorCode
}
Der Trick ist einfach den ErrorCode im lambda von ensure oder ensureNotNull zu passen, damit spart man sich das extra wrapping. Und falls du in der Domain mit Null arbeiten musst oder sollst dann kann man auch mit Option.fromNullable.
Falls du noch fragen hast sag bescheid 😄raulraja
06/01/2022, 10:06 PMImran/Malic
06/01/2022, 10:09 PMshift
will propagate the Error value and there is no need for OptionMoritz Lindner
06/02/2022, 7:14 AMMoritz Lindner
06/04/2022, 1:04 PMEither<A, B>
and made the Not Found Case part of the left. Therefore my whole question was unimportant in the end...
But I am still glad that I because I still learned some things 🙂 So a big thx to you towImran/Malic
06/04/2022, 1:23 PM