Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should we merge Error.Message and Error.Exception? #231

Closed
eyalgu opened this issue Sep 17, 2020 · 7 comments
Closed

Should we merge Error.Message and Error.Exception? #231

eyalgu opened this issue Sep 17, 2020 · 7 comments
Labels
discussion we are discussing what to do, usually based on some feature request or comment enhancement New feature or request

Comments

@eyalgu
Copy link
Contributor

eyalgu commented Sep 17, 2020

We've received feedback from alpha users that StoreResponse has too many subclasses which make it annoying to handle.

I'm not sure if there's a clean way to merge them together if we want to support non exception error handling as a first class citizen.

The "easy" way to do it would be to make StoreResponse generic on the error type as well:

sealed class StoreResponse<out DATA, out ERROR> {
  class Data<out DATA> : StoreResponse<DATA, Nothing>()
  class Error<out ERROR> : StoreResponse<Nothing, ERROR>()
}
@eyalgu eyalgu added enhancement New feature or request discussion we are discussing what to do, usually based on some feature request or comment labels Sep 17, 2020
@eyalgu eyalgu linked a pull request Sep 17, 2020 that will close this issue
@ferinagy
Copy link
Contributor

I must say, that I am not a fan of this change. Especially StoreBuilder.from() now with 4 parameters...

I would still vote for just removing a StoreResponse.Error.Message. After first a deeper look, I see that if there is a fetcher that returns FetcherResult.Message, it will be mapped to the corresponding StoreResponse.Error.Message state. But if someone wants to use some network call that returns some NetworkResult, it still needs to be mapped to a FetcherResult. Then it is still possible to map an error with a message to a StoreResponse.Error(Throwable(message)).

If that is a no go, then I would rather keep current state than adding more generic parameters.

@eyalgu
Copy link
Contributor Author

eyalgu commented Sep 17, 2020

Thanks for the feedback and for helping get the best API we can!

The reason I don't want to limit error type to be only exception is that there's a general move away from using exception to report errors from things like network etc.

as for the concern re StoreBuilder.from - Throwable should be inferred for users who use exceptions because Fetcher#of hard codes Error = Throwable

val store1 = StoreBuilder.from(Fetcher.of {key : Int -> key.toString() }).build()

val sot = SourceOfTruth.of(
    nonFlowReader = { k: String -> k },
    writer = {_: String, _: String -> Unit }
)
val store2 = StoreBuilder.from(Fetcher.of {key : String -> key }, sot).build()

@eyalgu
Copy link
Contributor Author

eyalgu commented Sep 17, 2020

but yeah, the extra generic is definitely a downside of this change that I want to have a bigger discussion on.

@digitalbuddha
Copy link
Contributor

I'm with @ghus-raba StoreResponse.Error(Throwable(message)) seems reasonable enough to handle messages as StoreResponse.Error. 1-2 generics was ok 4 is a bit more than what I'd want from a user experience

@yigit
Copy link
Collaborator

yigit commented Sep 21, 2020

+1.
Also, what is the problem w/ having their own exception classes?
They can even write extension fields to StoreResponse that will convert the error.

My vote is to keep it as it, making error generic complicates the APIs even further and I don't think it is worth it. At least not in this version.

@JavierSegoviaCordoba
Copy link

JavierSegoviaCordoba commented Jan 10, 2021

I like the OP sealed class which is similar to Either.

I would like something similar to:

sealed class StoreResponse<out D, out E> {
  data class Data<out D>(val data: D, val isLoading:  Boolean) : StoreResponse<D, Nothing>()
  data class Error<out D, out E>(val error: E, val fallbackData: D?, val isLoading: Boolean) : StoreResponse<D, E>()
}

Maybe isLoading property could be added to StoreResponse. If not, a val StoreResponse.isLoading: Boolean extension function should be great.

With that sealed class you could do all possible escenarios:

  • success with no data
  • success with no data + loading
  • success with data + loading
  • success with data
  • error
  • error + loading
  • error + loading + data
  • error + data

I like the generic error approach but if it can be a problem, it could be:

sealed class StoreResponse<out D> {
  data class Data<out D>(val data: D, val isLoading:  Boolean) : StoreResponse<D>()
  data class Error<out D>(val error: Throwable, val fallbackData: D?, val isLoading: Boolean) : StoreResponse<D>()
}

In my case I would like to abstract all datasources using domain models (which implies using domain error models too instead of propagate exceptions). If Store could hang error models instead of only exceptions should be great because probably I could avoid mapping the Throwable to some generic error later instead of using directly the abstractions.

@digitalbuddha
Copy link
Contributor

closing for now, might approach again in next version of store. StoreResponse.Error(Throwable(message)) gives users the ability to map any throwable/response type toa StoreResponse.Error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion we are discussing what to do, usually based on some feature request or comment enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants