Hi!. In this video (at the playback point on the l...
# arrow
j
Hi!. In this video (at the playback point on the link) an alternative way to model domain errors with extension functions and not requiring sealed / shared inheritance was hinted:

https://www.youtube.com/watch?v=g79A6HmbW5M&t=1786s

Is that on any code example / talk done afterwards already? I’m experimenting with things there, but would like to know the approach suggested on the talk cause it may be better / different and it would be nice to see before choosing something.
@simon.vergauwen?
s
Hey @jrgonzalez, Great question. I didn’t have enough time to show everything in the webinar sadly 😜 Let’s say you have the following:
Copy code
data class DatabaseError(val error: Throwable)
data class NetworkError(val error: Throwable)
Normally you’d combine them under a common parent using
sealed interface MyError
so that you can have
Either<MyError, A>
. But with context receivers you can do:
Copy code
context(
  EffectScope<DatabaseError>,
  EffectScope<NetworkError>
)
suspend fun program(): A
This can be good for multiple reasons: • Doesn’t require inheritance, or common parents. So it allows you to keep clear seperation of concern between errors. • It allows you to resolve specific errors, or install error handlers for specific types, wherever you want. I.e. you can resolve
DatabaseError
but leave the
NetworkError
for another layer.
Copy code
context(EffectScope<NetworkError>)
suspend fun programOrNull(): A? =
  effect<DatabaseError, A> {
    program()
  }.orNull()
I need more time to make content around these topics 🙈
j
thanks for the quick reply!, that certain looks cool 👌 Sadly I can’t use context receivers yet on production code (even JetBrains says so). I thought you meant something with extension functions (like manual exhaustive folds) which I also tried but did not arrive yet at anything super clean / low maintenance. Maybe I need to wait then for context receivers to become stable, looking forward to that! 😄
s
The only other way I know this is possible is by using something like
Coproduct
or
Union
(
abstract common parent
) in the
Left
side, but that typically doesn’t result in less boilerplate or cleaner code than if you use a
concrete common parent
.
j
yes, my other compromise solution would be to have
DomainError
as a shared type across compilation modules and just check on subtypes I can handle at the specific effect (or map left to something else). That may be what I would go for since the attempts to fold over not sealed hierarchies is doubtfully better. Some subtypes of DomainError when contained within a single module could still be sealed too, like you do in your webinar code with subtypes of DomainError that are also sealed 👌
a
Awesome!!! Very useful for me. Now I know how to use Context Receiver. Thanks @simon.vergauwen