Patrick Ramsey
06/14/2021, 11:22 PMwhen (sendCommand(val result = command)) {
is Result.Success<CommandResponse> -> Result.Success(getDerivedValue(result))
is Result.SomeFailure<CommandResponse> -> Result.SomeFailure(result.message)
is Result.OtherFailure<CommandResponse> -> Result.OtherFailure(result.message)
}
I canāt think of a better way, but this feels incredibly boilerplatey ā Iād love to be able to just return the underlying errors (since thatās what the caller will care about), but that doesnāt work since the generic type parameter is changing (even though the error subtypes donāt actually make use of the type parameter).
Alternatively, I could just hide the error, and present these fields as properties that are null if the lookup failed. But then Iāve robbed the caller of the ability to respond meaningfully to the failure.
TL;DR: is there any good pattern for forwarding a lower-level error up the call stack, where appropriate? Because I can certainly think of cases where that seems very appropriate.Patrick Ramsey
06/14/2021, 11:35 PMJoffrey
06/14/2021, 11:36 PMmap()
function on the generic result sealed class, so you don't have to repeat this when
for every different commandPatrick Ramsey
06/14/2021, 11:36 PMPatrick Ramsey
06/14/2021, 11:36 PMPatrick Ramsey
06/14/2021, 11:37 PMPatrick Ramsey
06/14/2021, 11:37 PMPatrick Ramsey
06/14/2021, 11:38 PMPatrick Ramsey
06/14/2021, 11:38 PMPatrick Ramsey
06/14/2021, 11:38 PMPatrick Ramsey
06/14/2021, 11:38 PMNir
06/14/2021, 11:38 PMJoffrey
06/14/2021, 11:38 PMJoffrey
06/14/2021, 11:39 PMsealed class Result<out T> {
data class Success<T>(val value: T): Result<T>() {
override fun <U> map(transform: (T) -> U): Result<U> = Success(transform(value))
}
class SomeError<T>(val message: String) : Result<T>() {
override fun <U> map(transform: (T) -> U): Result<U> = SomeError(message)
}
class OtherError<T>(val throwable: Throwable) : Result<T>() {
override fun <U> map(transform: (T) -> U): Result<U> = OtherError(throwable)
}
abstract fun <U> map(transform: (T) -> U): Result<U>
}
Nir
06/14/2021, 11:39 PMNir
06/14/2021, 11:39 PMNir
06/14/2021, 11:40 PMResult<T>
is that you want to at least have the option to also be generic on the type of the error, IMHOJoffrey
06/14/2021, 11:41 PMNir
06/14/2021, 11:41 PMPatrick Ramsey
06/14/2021, 11:41 PMJoffrey
06/14/2021, 11:41 PMNir
06/14/2021, 11:42 PMPatrick Ramsey
06/14/2021, 11:42 PMPatrick Ramsey
06/14/2021, 11:42 PMNir
06/14/2021, 11:42 PMJoffrey
06/14/2021, 11:43 PMNir
06/14/2021, 11:43 PMPatrick Ramsey
06/14/2021, 11:43 PMJoffrey
06/14/2021, 11:43 PMPatrick Ramsey
06/14/2021, 11:45 PMPatrick Ramsey
06/14/2021, 11:45 PMJoffrey
06/14/2021, 11:46 PMyeah, but then you're re-implementing map and things like thatThis is a reasonable price if the number of error types is small and/or if they encapsulate more than one property. For multi-property errors, you would have to have more wrapping if you want a single type parameter
Patrick Ramsey
06/14/2021, 11:46 PMPatrick Ramsey
06/14/2021, 11:46 PMPatrick Ramsey
06/14/2021, 11:47 PMJoffrey
06/14/2021, 11:47 PMPatrick Ramsey
06/14/2021, 11:48 PMPatrick Ramsey
06/14/2021, 11:48 PMPatrick Ramsey
06/14/2021, 11:48 PMPatrick Ramsey
06/14/2021, 11:49 PMPatrick Ramsey
06/14/2021, 11:49 PMPatrick Ramsey
06/14/2021, 11:50 PMPatrick Ramsey
06/14/2021, 11:50 PM@Patrick RamseyĀ I think I understand better your problem now, thanks for the detailsAnd thank you!
Patrick Ramsey
06/14/2021, 11:55 PMPatrick Ramsey
06/14/2021, 11:56 PMNir
06/14/2021, 11:58 PMPatrick Ramsey
06/14/2021, 11:58 PMNir
06/14/2021, 11:58 PMPatrick Ramsey
06/14/2021, 11:58 PMNir
06/14/2021, 11:58 PMPatrick Ramsey
06/14/2021, 11:58 PMNir
06/14/2021, 11:59 PMPatrick Ramsey
06/15/2021, 12:00 AMNir
06/15/2021, 12:00 AMPatrick Ramsey
06/15/2021, 12:00 AMNir
06/15/2021, 12:00 AMNir
06/15/2021, 12:01 AMNir
06/15/2021, 12:01 AMJoffrey
06/15/2021, 12:01 AMPatrick Ramsey
06/15/2021, 12:02 AMPatrick Ramsey
06/15/2021, 12:02 AMNir
06/15/2021, 12:02 AMPatrick Ramsey
06/15/2021, 12:02 AMPatrick Ramsey
06/15/2021, 12:02 AMPatrick Ramsey
06/15/2021, 12:02 AMNir
06/15/2021, 12:03 AMPatrick Ramsey
06/15/2021, 12:03 AMJoffrey
06/15/2021, 12:03 AMNir
06/15/2021, 12:03 AMNir
06/15/2021, 12:03 AMPatrick Ramsey
06/15/2021, 12:03 AMPatrick Ramsey
06/15/2021, 12:03 AMI suppose one option would be to have a separate DeviceError sealed type, and define my errors there and have the Result type refer to it.Ā Iāll do that.
Nir
06/15/2021, 12:03 AMPatrick Ramsey
06/15/2021, 12:04 AMPatrick Ramsey
06/15/2021, 12:05 AMPatrick Ramsey
06/15/2021, 12:05 AMNir
06/15/2021, 12:05 AMNir
06/15/2021, 12:06 AMNir
06/15/2021, 12:06 AMNir
06/15/2021, 12:06 AMPatrick Ramsey
06/15/2021, 12:06 AMPatrick Ramsey
06/15/2021, 12:06 AMNir
06/15/2021, 12:07 AMPatrick Ramsey
06/15/2021, 12:07 AMNir
06/15/2021, 12:07 AMPatrick Ramsey
06/15/2021, 12:07 AMNir
06/15/2021, 12:07 AMJoffrey
06/15/2021, 12:07 AMResult
type with 2 generic params, and nice operators to go with it:
https://github.com/michaelbull/kotlin-resultPatrick Ramsey
06/15/2021, 12:08 AMNir
06/15/2021, 12:08 AMPatrick Ramsey
06/15/2021, 12:08 AMPatrick Ramsey
06/15/2021, 12:08 AMNir
06/15/2021, 12:09 AMPatrick Ramsey
06/15/2021, 12:09 AMJoffrey
06/15/2021, 12:09 AMPatrick Ramsey
06/15/2021, 12:09 AMNir
06/15/2021, 12:09 AMPatrick Ramsey
06/15/2021, 12:09 AMPatrick Ramsey
06/15/2021, 12:09 AMNir
06/15/2021, 12:10 AMNir
06/15/2021, 12:10 AMPatrick Ramsey
06/15/2021, 12:10 AMPatrick Ramsey
06/15/2021, 12:10 AMJoffrey
06/15/2021, 12:10 AMNir
06/15/2021, 12:10 AMJoffrey
06/15/2021, 12:11 AMwhen
expressions + smart cast is the language support for thatNir
06/15/2021, 12:13 AMNir
06/15/2021, 12:13 AMNir
06/15/2021, 12:14 AMPatrick Ramsey
06/15/2021, 12:15 AMwhen (someResult) {
is Success -> ...
is Error -> ....
}
Success and Error are Result.Success and Result.Error, without having to explicitly specify it.Nir
06/15/2021, 12:16 AMNir
06/15/2021, 12:16 AMJoffrey
06/15/2021, 12:16 AMThere's no support for propagation is what I should say, whereas obviously there is for exceptionsI see your point, thanks
Nir
06/15/2021, 12:16 AMNir
06/15/2021, 12:17 AMPatrick Ramsey
06/15/2021, 12:17 AMNir
06/15/2021, 12:18 AMPatrick Ramsey
06/15/2021, 12:18 AMJoffrey
06/15/2021, 12:18 AMSometimes you may call a function that can fail with inputs such that you know it shouldn't ever fail, in that case you just want a way to unwrap the valueI think that is the point of unchecked exceptions, precisely. It's about trusting that you're calling the methods with the correct arguments, and thus not bloating the type system and the code with error checking (and yet still be able to catch errors, should they arise)
Patrick Ramsey
06/15/2021, 12:21 AMPatrick Ramsey
06/15/2021, 12:21 AMPatrick Ramsey
06/15/2021, 12:21 AMPatrick Ramsey
06/15/2021, 12:22 AMJoffrey
06/15/2021, 12:22 AMPatrick Ramsey
06/15/2021, 12:22 AMPatrick Ramsey
06/15/2021, 12:22 AMPatrick Ramsey
06/15/2021, 12:22 AMPatrick Ramsey
06/15/2021, 12:23 AMPatrick Ramsey
06/15/2021, 12:24 AMNir
06/15/2021, 12:42 AMNir
06/15/2021, 12:42 AMPatrick Ramsey
06/15/2021, 1:08 AMPatrick Ramsey
06/15/2021, 1:08 AMPatrick Ramsey
06/15/2021, 2:02 AMI suppose one option would be to have a separate DeviceError sealed type, and define my errors there and have the Result type refer to it.made things embarrassingly easy. Iām annoyed at myself
Patrick Ramsey
06/15/2021, 2:03 AMPatrick Ramsey
06/15/2021, 2:04 AMephemient
06/15/2021, 4:10 AMephemient
06/15/2021, 4:12 AM