Skip to content

Instantly share code, notes, and snippets.

@ezura
Forked from inamiy/typed-error-poem.md
Created November 3, 2017 21:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ezura/03bbfe5dd8dc1a7c53d2198bd336dfee to your computer and use it in GitHub Desktop.
Save ezura/03bbfe5dd8dc1a7c53d2198bd336dfee to your computer and use it in GitHub Desktop.
Swift Poem: Why I prefer typed error (for https://github.com/apple/swift-evolution/pull/757)

Typed error can be useful in certain cases, especially when accompanied with NoError type.

For example, in reactive programming, https://github.com/ReactiveCocoa/ReactiveSwift (typed error) allows us to create UI bindings only if Error is NoError, i.e.:

static func <~ <Source: BindingSource> (provider: Self, source: Source) -> Disposable? 
    where Source.Value == Value, Source.Error == NoError { ... }
    
// example
let alphaSignal: Signal<CGFloat, NoError> = ...
view.reactive.alpha <~ alphaSignal

This makes sense since UI binding only requires values to be sent, and not for errors. Signal<T, NoError> clearly defines that this instance will never send error during its lifetime.

On the contrary, in https://github.com/ReactiveX/RxSwift (untyped error) for example, we need some runtime check (e.g. fatalError("don't send error")) before making a safe(?) UI binding, since Observable<T> doesn't guarantee it doesn't emit error. That's why there are many attempts to ease the situation, e.g. Driver, PublishRelay, etc, but I don't think there could be any best compile-time solution for this problem without the help of type-system. (There's ongoing discussion in ReactiveX/RxSwift#1470 for more detail)

Obviously, this can be said for Result<T, E> type as well. Result<T, NoError> will express the success-only data, and this is also useful when there is a function that converts from Signal<T, NoError> to Result<T, NoError>, e.g. ReactiveSwift's SignalProducer.single().

Without Result<T, NoError>, the implementation of func single() -> Result<Value, Error>? will probably be splitted into 2 overloaded methods:

extension SignalProducer {
	public func first() -> Result<Value>? { ... }
}
extension SignalProducer where Error == NoError {
	// NOTE: We don't want to use `Result<Value>?` as return type 
	// because we already know it doesn't emit error.
	public func first() -> Value? { ... }
}

which will be :sadtroll:.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment