Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Result<T> V.S. Result<T, E> (English)

Result<T> V.S. Result<T, E> (English)

try! Swift Tokyo 2018 After talks (Mar 08, 2018)
https://tryswifttokyo-aftertalks.connpass.com/event/79689/

Yasuhiro Inami

March 08, 2018
Tweet

More Decks by Yasuhiro Inami

Other Decks in Programming

Transcript

  1. // Without error type parameter public enum Result<Value> { case

    success(Value) case failure(Swift.Error) } // V.S. // With error type parameter public enum Result<Value, Error: Swift.Error> { case success(Value) case failure(Error) }
  2. Result<T, E> (V.S. Result<T>) • GOOD • Can contain error

    "type" (not only error "value"!) • Represents error domain (where error comes from) • Exhaustive error pattern matching • BAD • mapError is required per error domain switching • Nested enum errors
  3. What BAD people say: "There is no need to check

    errors exhaustively" "To check a specific error, just using as? casting is sufficient"
  4. What is NoError ? • enum NoError: Swift.Error {} •

    Can't create value (e.g. Never) • NoError is also an Error • Represents "0" of algebraic data type • Zero (bottom) type enriches type representation
  5. // Example: ReactiveSwift UI Binding // (Can be used ONLY

    WHEN `Error == NoError`) static func <~ <Source: BindingSource> ( provider: Self, source: Source ) -> Disposable? where Source.Value == Value, Source.Error == NoError { ... } // Binding let alphaSignal: Signal<CGFloat, NoError> = ... view.reactive.alpha <~ alphaSignal
  6. Usage of NoError • Signal<Value, NoError> • Observable type that

    never errors out • No need to create another type, e.g. RxSwift.Driver • Result<Value, NoError> • Represents succcessful value only (Can't be described using Result<Value>) • Shouldn't we just use plain Value instead? → NO!
  7. Result<Value, NoError> Value If we have a function of Observable<T,

    E> -> Result<T, E> (e.g. ReactiveSwift.first): In Result<T, E> world... extension SignalProducer { public func first() -> Result<Value, Error>? { ... } }
  8. In Result<T> world... extension SignalProducer { // This `self` may

    error out, so we use `Result<Value>?` public func first() -> Result<Value>? { ... } } extension SignalProducer where Error == NoError { // This `self` will NEVER errors out (by `where` constraint), // so we don't want to use `Result<Value>?` here! public func first() -> Value? { ... } } Different type signature = meaningless overload !"
  9. Mathematically speaking... • Result<Value, NoError> Value • Not exactly the

    same, but isomorphic (invertible) • For more info, dive to Category Theory • NoError is "0" • Useful for non-error handling, which is also a part of error handling! • Result<T> / Observable<T> are the world without zero