Slide 1

Slide 1 text

CORRECT BEHAVIOR THROUGH TYPE SAFETY

Slide 2

Slide 2 text

@JSPAHRSUMMERS REACTIVECOCOA MANTLE CARTHAGE

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

TYPES PREVENT ERRORS (by restricting what you can do)

Slide 5

Slide 5 text

NSArray IS MORE RESTRICTED THAN NSMutableArray

Slide 6

Slide 6 text

NSArray PREVENTS MORE ERRORS THAN NSMutableArray

Slide 7

Slide 7 text

Optional RESTRICTS ACCESS TO ITS VALUE PREVENTS MISTAKES WITH nil

Slide 8

Slide 8 text

Array RESTRICTS INSERTIONS PREVENTS CRASHES AFTER RETRIEVAL

Slide 9

Slide 9 text

More generally…

Slide 10

Slide 10 text

TYPES = PROOFS (the Curry–Howard correspondence)

Slide 11

Slide 11 text

A → B

Slide 12

Slide 12 text

A → B func toInteger(num: Double) -> Int { let result = round(num) return Int(result) }

Slide 13

Slide 13 text

STRING → STRING

Slide 14

Slide 14 text

STRING → STRING func identity(s: String) -> String { return s }

Slide 15

Slide 15 text

WE CAN USE TYPES TO PROVE CORRECTNESS

Slide 16

Slide 16 text

WHAT DOES NSDATA PROVE? (Not much.)

Slide 17

Slide 17 text

WHAT DOES NSSTRING PROVE? Characters, not just bytes!

Slide 18

Slide 18 text

WHAT DOES NSURL PROVE? Valid URL, not just a string!

Slide 19

Slide 19 text

EXTENDS TO ANY KIND OF VALIDATION

Slide 20

Slide 20 text

What about tests?

Slide 21

Slide 21 text

Science break!

Slide 22

Slide 22 text

TESTS ARE SUPPORT TYPES ARE PROOF

Slide 23

Slide 23 text

Caveats ▸ Proofs can contain errors too ▸ Types can’t represent everything ▸ Tests may be good enough

Slide 24

Slide 24 text

No content

Slide 26

Slide 26 text

Case study: ERRORS IN REACTIVECOCOA

Slide 27

Slide 27 text

SIGNALS CONSIST OF… ▸ Any number of next events ▸ Optionally an error or completed event Next* (Error | Completed)?

Slide 28

Slide 28 text

RACSignal *

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

PROPERTY BINDING IN RAC 2 RAC(self.imageView, image) = [RACObserve(self, model) flattenMap:^ RACSignal * (Model *model) { return [model fetchImage]; }];

Slide 31

Slide 31 text

PROPERTY BINDING IN RAC 2 RAC(self.imageView, image) = [RACObserve(self, model) flattenMap:^ RACSignal * (Model *model) { return [model fetchImage]; }]; *** Received error from RACSignal in binding for key path "image" on UIImageView: Error Domain=NSURLErrorDomain Code=-1 "Operation could not be completed."

Slide 32

Slide 32 text

Solution: TYPES!

Slide 33

Slide 33 text

Signal

Slide 34

Slide 34 text

enum NoError {}

Slide 35

Slide 35 text

PROPERTY BINDING IN RAC 3 func <~ (property: MutableProperty, signal: Signal) func <~ (property: MutableProperty, producer: SignalProducer)

Slide 36

Slide 36 text

PROPERTY BINDING IN RAC 3 class Model { func fetchImage() -> SignalProducer } self.imageProperty <~ self.modelProperty.producer // TYPE ERROR: NSError is incompatible with NoError |> flatMap(.Latest) { model in return model.fetchImage() }

Slide 37

Slide 37 text

PROPERTY BINDING IN RAC 3 class Model { func fetchImage() -> SignalProducer } self.imageProperty <~ self.modelProperty.producer |> flatMap(.Latest) { model in return model.fetchImage() // Ignore any error event |> catch { error in .empty } }

Slide 38

Slide 38 text

TYPED ERRORS VS. throws

Slide 39

Slide 39 text

TYPES CAN ALSO DESCRIBE EFFECTS

Slide 40

Slide 40 text

IO MONAD IN HASKELL

Slide 41

Slide 41 text

WITH IO, YOU CAN… ▸ Put a value into it ▸ Perform side effects using the value ▸ “Lift” pure functions to apply to the value ▸ Never2 get the result back out 2 Except through the rarely-used unsafePerformIO.

Slide 42

Slide 42 text

WITH A SIGNAL, YOU CAN… ▸ Put values into it ▸ Perform time-based operations using the values ▸ “Lift” pure functions to apply to the values ▸ Register for delivery3 to get the results back out 3 It’s possible to synchronously wait for results, but the framework highly discourages this.

Slide 43

Slide 43 text

Example: TYPES FOR CONCURRENCY

Slide 44

Slide 44 text

THE UI PROBLEM™ dispatch_async(someBackgroundQueue) { // Oops! self.textField.text = "foobar" }

Slide 45

Slide 45 text

CAPTURING UI CODE IN THE TYPE SYSTEM struct UIAction { init(_ action: () -> T) func enqueue() func enqueue(handler: T -> ()) func map(f: T -> U) -> UIAction func flatMap(f: T -> UIAction) -> UIAction }

Slide 46

Slide 46 text

WHAT IF…? extension UITextField { /// Sets the receiver's text to the given string /// when the returned action is executed. func jss_setText(text: String) -> UIAction<()> }

Slide 47

Slide 47 text

SLIDES AND NOTES Available at git.io/vkjl9 (github.com/jspahrsummers/correct-behavior-through-type-safety) THANKS TO… Neil Pankey, Rob Rix, James Lawton, Gordon Fontenot, Eli Perkins, Javi Soto, anyone else who I omitted in error, and you!