Skip to content

Instantly share code, notes, and snippets.

@inamiy
Last active November 8, 2018 13:58
Show Gist options
  • Save inamiy/e3f5f7524f1bcdc582c2ff8dbbba58dd to your computer and use it in GitHub Desktop.
Save inamiy/e3f5f7524f1bcdc582c2ff8dbbba58dd 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:.

@inamiy
Copy link
Author

inamiy commented Nov 22, 2017

Slide (in Japanese): Result V.S. Result<T, E> // Speaker Deck

In the talk, I gave the above example code to illustrate:

  • How Result<T> fails the abstraction of parametric polymorphism by having boring overloaded code
  • Result<Value, NoError> is isomorphic to Value
  • How NoError is important for Non- Error-handling as well

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