I would like to read about the reasoning for not having typed errors like RAC does. Is there any place I can read about it? RAC's arguments seems pretty sensable to me:
When signals and signal producers are allowed to fail in ReactiveCocoa, the kind of error must be specified in the type system. For example, Signal
is a signal of integer values that may fail with an error of type NSError. More importantly, RAC allows the special type NoError to be used instead, which statically guarantees that an event stream is not allowed to send a failure. This eliminates many bugs caused by unexpected failure events.
In Rx systems with types, event streams only specify the type of their values—not the type of their errors—so this sort of guarantee is impossible.
https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/README.md
And what's stated here has interesting points as well
In ReactiveCocoa, since you “fix” the type when you create a Signal
or a SignalProducer , the compiler will complain if you try to send something else. Bottom line: in ReactiveCocoa, the compiler won’t allow you to send a different error than the one you are expecting.
https://www.raywenderlich.com/126522/reactivecocoa-vs-rxswift
I can't speak to Kruno's intentions, but typed errors are a matter of preference. Like most things in programming, there isn't an unequivocal right or wrong answer. Take Swift for example: it doesn't have typed errors even though it might make sense. I've personally never found a situation where I needed typed errors, and I can see that flatMapping across several observable types could produce a headache of cascading error types, or a MegaError enum. But again, that's just me – everyone has a difference opinion and preference. If you do need them and want to use RxSwift, you can have an Observable<Result<ValueType, ErrorType>> that produces typed errors for you.
Thanks for pointing out that perspective.
Hi @hfossli ,
Thxn @ashfurrow for answering, was little busy :) I guess I can provide a more elaborate explanation how I see things.
This is a complex question that, like all other things in life, has it's pros and cons. I guess since you've pasted those links, I can give my short summary on the question you were asking.
Since this issue references other projects and their contributors and can potentially provide certain individuals a fruitful playground--and I really don't want to waste time and energy on internet wars--I'm really sorry if I'll need to lock this conversation if something goes wrong with this thread.
This is my present view on this subject and hoping that maybe broader organization shares my opinions, but I haven't verified with them, nor can I speak in their name.
For TLDR folks, here is a quick summary of pros and cons of introducing typed errors for RxSwift 2.0 in Swift 2.0 and rationale why we are considering introducing it for RxSwift 3.0 :))))
I'm not assigning any weight to these pros on cons.
// can't express
func myFunction<MyErrorType>() throws MyErrorType -> ()
typealias Observable<E> = ObservableSomething<Element, ErrorType>Observable<String, NoError>.just("a") vs Observable.just("a")mapError* family)mapError* operators mentioned above)flatMapWithIndex when Index turns Int.max, what should the result error be? Should it be ErrorType, some enum that says did flatMapWithIndex fail or has error been propagated to it from source (in RxSwift 3.0 it will have ErrorType probably)NSError are dynamic by nature because when new iOS version is released you want your apps to continue working with new version out of the box. Having NSError type in a lot of places instead of ErrorType isn't any improvement IMHO.The main reason why we are planning to introduce it in RxSwift 3.0 because it is useful to more easily communicate that a sequence can't fail across interface boundaries, and it looks like Swift 3.0 will support parametrized error throwing and generic typealiases, so other drawbacks are remedied if we can define typealias Observable<E> = ObservableSomething<Element, ErrorType> and have the best of both worlds.
There isn't any clear winner as far as I can tell, there are just different tradeoffs, but hoping that with Swift 3.0 we'll be able to support all different usage scenarios.
Probably the most mundane reason why people want those TypedErrors is because of showing alert messages :) But will you want to ever show to you user "There was an error parsing JSON". Probably not.
There are always different ways how to think about systems. If there are some important cases you care about, then perhaps it's not best to model them as errors and use automatic propagation, but as return value enum so you need to manually decide for each caller site what to do in that novel case.
The other types of errors are more platform level failure errors, like network connectivity errors. You probably want to say for a certain class of errors in a type safe way how to present them in alert ways. Maybe creating a protocol like protocol PresentableErrorType { var presentableTitle: String? { get } var presentableMessage: String? { get } } and extending some user presentable errors makes sense, maybe not.
What I'm trying to say is that there are plethora of interesting solutions how to approach common problems and each of them has different tradeoffs.
That README.md is full of sensationalistic statements that aren't precise or true:
In Rx systems with types, event streams only specify the type of their values—not the type of their errors ...
To me Rx is an abstraction of sequence that can potentially fail with an error. That's it.
That's the only thing that is important.
Is that error typed or untyped is not important. It doesn't change anything about the concept. It doesn't add or remove some novel properties to the abstraction itself.
Having a typed error doesn't mean that you are breaking Rx abstraction in any way as far as I can tell.
It is true that so far most implementations have chosen to have untyped error, because implementations are highly dependent on the language they are implemented in and not many languages offer to parametrize on the throw type (that is also valid for Java as far as I can tell, because it has unchecked exceptions).
... so this sort of guarantee is impossible.
let xs = originalSequenceThatCanFail.catchError { _ in return Observable.empty() }
... can xs error out? I know that you are thinking that this is not equivalent to what that says in that README.md, but let me try to elaborate this.
Being able to communicate that sequence doesn't error out is just one of the properties that are useful to communicate across interface boundaries. There are also other properties like:
We've tried to think about how to solve these compile time guarantees in a general way. You can read more about it here.
I'm not arguing that the solution we are providing is perfect and flawless, but you can write really clean type safe code that way.
Interesting reading. Thank you for sharing your insight!
This could have probably be closed.
Most helpful comment
I can't speak to Kruno's intentions, but typed errors are a matter of preference. Like most things in programming, there isn't an unequivocal right or wrong answer. Take Swift for example: it doesn't have typed errors even though it might make sense. I've personally never found a situation where I needed typed errors, and I can see that flatMapping across several observable types could produce a headache of cascading error types, or a
MegaErrorenum. But again, that's just me – everyone has a difference opinion and preference. If you do need them and want to use RxSwift, you can have anObservable<Result<ValueType, ErrorType>>that produces typed errors for you.