Jakub Zalas
07/25/2023, 10:42 AMfun one(): Either<MyErrorType, Something>
then
fun two() : Either<MyOtherErrorType, Something>
I'd like to avoid MyErrorType
and MyOtherErrorType
being in the same error type hierarchy, so I probably need to map/wrap them to something common. Are there any known patterns to do that?Jakub Zalas
07/25/2023, 10:42 AMCLOVIS
07/25/2023, 11:37 AMsealed class FooError {
data class MyErrorType(val error: MyErrorType) : FooError()
data class MyOtherErrorType(val error: MyOtherErrorType) : FooError()
}
context(Raise<FooError>)
fun foo() {
withError(FooError::MyErrorType) { one() }
withError(FooError::MyOtherErrorType) { two() }
}
simon.vergauwen
07/25/2023, 11:41 AMCLOVIS
07/25/2023, 11:45 AMunion class FooError {
MyErrorType,
MyOtherErrorType,
}
…but well. Maybe after K2 they'll have more time to bring back the union types ticket to the table?Jakub Zalas
07/25/2023, 11:45 AMCLOVIS
07/25/2023, 11:46 AMJakub Zalas
07/25/2023, 11:48 AMsimon.vergauwen
07/25/2023, 11:48 AMsealed interface
instead of sealed class
. It easily allows for "composing hierarchies" without all this additional overhead. I just do it to avoid the boilerplate...
Maybe after K2 they'll have more time to bring back the union types ticket to the table?Their current focus is K2, they've mentioned that they expect an increase in velocity in other areas such as union/intersection types but their is also still some discussion about the syntax.
simon.vergauwen
07/25/2023, 11:50 AMUnion2
, Union3
, Union4
, etc which you could use as an generic solution for this as well.
sealed interfae Union2<out A, out B> {
data class First<A>(val value: A) : Union2<A, Nothing>()
data class Second<B>(val value: B) : Union2<Nothing, B>()
}
context(Raise<Union2<MyErrorType, MyOtherErrorType>)
fun foo() {
withError(Union2::First) { one() }
withError(Union2::Second) { two() }
}
simon.vergauwen
07/25/2023, 11:51 AMJakub Zalas
07/25/2023, 11:51 AMwithError
. I'll play with that!CLOVIS
07/25/2023, 11:52 AMwithError
is something I requested to make exactly this pattern possible 😅 it's new in 1.2.0 I thinksimon.vergauwen
07/25/2023, 11:53 AMwithError
was introduced in between 1.2.0-RC and 1.2.0 thanks to feedback from @CLOVIS 🥳Jakub Zalas
07/25/2023, 11:53 AMCLOVIS
07/25/2023, 11:53 AMFailure
• for each domain operation, I have a sealed interface that inherits from that entity's Failure
• for each possible error case, I have a data class or object that implements all interfaces corresponding to operations that can throw it.
Example: https://gitlab.com/opensavvy/formulaide/-/blob/main/core/core-users/src/commonMain/kotlin/User.kt?ref_type=heads#L183
I'm not saying it's the best way to do it (it's very verbose…), but with withError
it's a lot simpler. I'm going to continue iterating over it until I find something I'm happy withCLOVIS
07/25/2023, 11:55 AMJakub Zalas
07/25/2023, 11:55 AMCLOVIS
07/25/2023, 11:56 AMCLOVIS
07/25/2023, 11:56 AMCLOVIS
07/25/2023, 11:57 AMCLOVIS
07/25/2023, 11:59 AMsimon.vergauwen
07/25/2023, 11:59 AMJakub Zalas
07/25/2023, 11:59 AM