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/

Eac0bf787b5279aca5e699ece096956e?s=128

Yasuhiro Inami

March 08, 2018
Tweet

Transcript

  1. try! Swift Tokyo 2018 #tryswiftconf

  2. None
  3. let trySwift = .success(!)

  4. let trySwift: Result<???> = .success(!)

  5. Result<T> V.S. Result<T,E> 2018/03/08 try!Swift Tokyo 2018 After talks Yasuhiro

    Inami / @inamiy
  6. // 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) }
  7. None
  8. None
  9. 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
  10. What BAD people say: "There is no need to check

    errors exhaustively" "To check a specific error, just using as? casting is sufficient"
  11. What GOOD people say: Error type is NOT just for

    error handling
  12. NoError Uninhabited (empty) error type

  13. 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
  14. // 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
  15. 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!
  16. 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>? { ... } }
  17. 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 !"
  18. 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
  19. Swift Poem: Why I prefer typed error https://gist.github.com/inamiy/ e3f5f7524f1bcdc582c2ff8dbbba58dd

  20. let trySwift: Result<???> = .success(!)

  21. let trySwift: Result<Emoji, NoError> = .success(!)

  22. Thanks! Yasuhiro Inami @inamiy