Alexander Weickmann
03/01/2023, 3:51 PMsimon.vergauwen
03/01/2023, 3:55 PMsimon.vergauwen
03/01/2023, 3:56 PMAlexander Weickmann
03/01/2023, 4:06 PMAlexander Weickmann
03/01/2023, 4:07 PMsimon.vergauwen
03/01/2023, 4:11 PMEither
and thus also bind
. In combination with Arrow and the awesome DSL support we have in Kotlin it'll offer a modern and functional alternative to typed exceptions.
Something that in (modern) FP is sometimes referred to as Effects (Handlers).Alexander Weickmann
03/01/2023, 4:12 PMsimon.vergauwen
03/01/2023, 4:13 PMobject MyError
fun Raise<MyError>.example(): Int =
raise(MyError)
fun Raise<MyError>.two(): Int =
one() + one()
// Materialise
either {
two()
} shouldBe Either.Left(MyError)
simon.vergauwen
03/01/2023, 4:19 PMEffectScope
& EagerEffectScope
have been flattened into Raise
and there is no longer a need to distinct between the two. Neither between either { }
and either.eager { }
. We've added a bunch of DSLs around Raise
which was possible due to the much more flexible implementation, so it's easy to install error handlers etc.
I.e. (continues on above example)
fun recovered(): Int =
recover({ one() }) { _: MyError -> 0 }
object OtherError
fun Raise<OtherError>.mapsError(): Int =
recover({ one() }) { raise(OtherError) }
fun Raise<MyError>.wrapDatabase(): User =
catch({ query("...").toUser() } { t: PSQLException -> raise(MyError) }
All previous code like either { }
, with bind()
, etc will all remain valid and all these DSLs are useable and compatible with each other. So no previous code needs to be changed, and you can adopt whatever you prefer or makes sense for your use-cases / team preference. Raise
is what powers the either { }
DSLs.Alexander Weickmann
03/01/2023, 4:42 PMeither { }
is still deprecated and will be removed for effect { }
, right?simon.vergauwen
03/01/2023, 4:47 PMeither { }
is not deprecated (and it never was?). With these new changes Effect
becomes a typealias Effect<E, A> = suspend Raise<E>.() -> A
. So the equivalent of the function signatures I wrote above, but as a lambda.
The problem with suspend
lambdas is that they don't have great support except for suspend () -> A
, and with effect { }
we can also leverage @BuilderInference
so effect { }
is just a utility function for providing better syntax when constructing these lambdas.
Besides it becoming a simple typealias, leveraging lambdas instead of it being an interface
also offers a bunch of performance benefits. This makes either { }
& bind
cost-free, and "as-expensive" as a single flatMap
.
However Either
is still a val
where Effect
is a lambda. So you could actually say that Either
is the natural result of execution the Effect
lambda. Making it concrete can be done by effect { }.toEither()
which is the (~) implementation of either { }
.Alexander Weickmann
03/01/2023, 4:52 PMAlexander Weickmann
03/01/2023, 4:54 PMsimon.vergauwen
03/01/2023, 5:00 PM1.1.6-alpha.39
. Alpha releases are guaranteed to be binary compatible with 1.x.x series, but unreleased code is prone to breaking changes.Alexander Weickmann
03/01/2023, 5:06 PMEmil Kantis
03/01/2023, 9:17 PMsimon.vergauwen
03/02/2023, 1:03 PMx
it then fails to compile.
either {
val x = returnsEither()
1
}
A second problematic case could still be a program returning Unit
, since () -> Unit
can swallows any returned value π
either<String, Unit> {
returnsEither()
}
It's still an improvement without requiring Detekt, but requires putting CheckResult
annotations on code. Not sure if Kotlin has module-wide annotations like Java for NotNull
? π€ Never tried that.Emil Kantis
03/02/2023, 1:21 PMEmil Kantis
03/02/2023, 2:17 PMsimon.vergauwen
03/02/2023, 2:18 PMalt+enter
refactoring.simon.vergauwen
03/02/2023, 2:18 PMhttps://i.kym-cdn.com/photos/images/newsfeed/001/373/328/b16.jpgβΎ