Slide 1

Slide 1 text

Type Driven Development Попов Валерий

Slide 2

Slide 2 text

TESTS

Slide 3

Slide 3 text

TESTS TESTS TESTS ESTS TEST TESTS TESTS TESTS ESTS TEST TESTS TESTS TESTS ESTS TEST TESTS TESTS TESTS ESTS TEST TESTS TESTS TESTS ESTS TEST TESTS TESTS TESTS ESTS TEST

Slide 4

Slide 4 text

TYPES

Slide 5

Slide 5 text

Practical › Type systems › Using types
 Agenda Theoretical › Dependent types in Swift › Type DD approach


Slide 6

Slide 6 text

Static | Dynamic Categories Strong | Weak Implicit | Explicit

Slide 7

Slide 7 text

C/C++ Objective-C Swift Java C# Haskell Clojure Python Ruby JavaScript STATIC DYNAMIC

Slide 8

Slide 8 text

Objective-C id Haskell.Dynamic STATIC DYNAMIC

Slide 9

Slide 9 text

STRONG WEAK Swift Java C# Haskell Clojure Python Ruby JavaScript

Slide 10

Slide 10 text

Clojure Scala PHP Python C/C++ Java Haskell Objective-C IMPLICIT EXPLICIT

Slide 11

Slide 11 text

Scala Haskell Swift IMPLICIT EXPLICIT

Slide 12

Slide 12 text

Types define code

Slide 13

Slide 13 text

Python: weak, dynamic 13 def binary_search(l, value): low = 0 high = len(l)-1 while low <= high: mid = (low+high) if l[mid] > value: high = mid-1 elif l[mid] < value: low = mid+1 else: return mid return -1

Slide 14

Slide 14 text

Python: weak, dynamic 14 def binary_search(list, value): … else: return mid return -1

Slide 15

Slide 15 text

Python: weak, dynamic 15 def binary_search(list, value): …

Slide 16

Slide 16 text

Swift: static, strong 16 func binarySearch(xs: [T], x: T) -> Int? { var recurse: ((Int, Int) -> Int?)! recurse = {(low, high) in switch (low + high) / 2 { case _ where high < low: return nil case let mid where xs[mid] > x: return recurse(low, mid - 1) case let mid where xs[mid] < x: return recurse(mid + 1, high) case let mid: return mid }} return recurse(0, xs.count - 1) }

Slide 17

Slide 17 text

Swift: static, strong 17 func binarySearch (xs: [T], x: T) -> Int? { … }

Slide 18

Slide 18 text

Swift: static, strong 18 func binarySearch (xs: [T], x: T) -> Int? { … }

Slide 19

Slide 19 text

USING TYPES

Slide 20

Slide 20 text

Money transfer 20 struct FailedTransaction { let isRejected: Bool let isCancelled: Bool let notEnoughMoney: Amount? }

Slide 21

Slide 21 text

21 struct FailedTransaction { let isRejected: Bool let isCancelled: Bool let notEnoughMoney: Amount? } let transaction = FailedTransaction ( isRejected: true, isCancelled: true, notEnoughMoney: nil )

Slide 22

Slide 22 text

Product type 22 struct FailedTransaction { let isRejected: Bool let isCancelled: Bool let notEnoughMoney: Amount? }

Slide 23

Slide 23 text

Sum type 23 enum FailedTransaction { case rejected case cancelled case outOfMoney(Amount) }

Slide 24

Slide 24 text

24 let failedTransaction: FailedTransaction failedTransaction = .rejected enum FailedTransaction { case rejected case cancelled case outOfMoney(Amount) }

Slide 25

Slide 25 text

Keep types simple

Slide 26

Slide 26 text

Message sending 26 struct Message { let text: String var isEncrypted: Bool }

Slide 27

Slide 27 text

27 func send(message: Message) throws { if message.isEncrypted { print(message.text) } else { throw MessageError.unsecured } } struct Message { let text: String var isEncrypted: Bool }

Slide 28

Slide 28 text

28 func send(message: Message) throws { if message.isEncrypted { print(message.text) } else { throw MessageError.unsecured } } let message = Message(text: "Hi!", isEncrypted: false) send(message: message)

Slide 29

Slide 29 text

Runtime exception :( 29 let message = Message(text: "Hi!", isEncrypted: false) send(message: message)

Slide 30

Slide 30 text

Compile time? 30 struct Message { let text: String }

Slide 31

Slide 31 text

Compile time? 31 struct Message { let text: String } enum Encrypted {} enum PlainText {}

Slide 32

Slide 32 text

32 func send(message: Message) { print(message.text) } struct Message { let text: String } enum Encrypted {} enum PlainText {}

Slide 33

Slide 33 text

33 func send(message: Message) { print(message.text) } let message = Message(text: “Hi!”) send(message: message)

Slide 34

Slide 34 text

Compile time :) 34 let message = Message(text: “Hi!") send(message: message)

Slide 35

Slide 35 text

Phantom Types 35 let m1 = Message(text: “”) let m2 = Message(text: “”)

Slide 36

Slide 36 text

Make invalid states unacceptable

Slide 37

Slide 37 text

ERROR HANDLING

Slide 38

Slide 38 text

Error codes 38 int foo() { if (failed) { return -1; } return 0; }

Slide 39

Slide 39 text

Completion 39 typedef void (^Compl)(NSData,NSError*) 
 - (void)performTask:(Compl)completion{ … completion(nil, error) }

Slide 40

Slide 40 text

40 typedef void (^Compl)(NSData,NSError*) 
 - (void)performTask:(Compl)completion{ … completion(nil, nil) // ??? } typedef void (^Compl)(NSData,NSError*) 
 - (void)performTask:(Compl)completion{ … completion(data, error) // ??? }

Slide 41

Slide 41 text

Exceptions 41 void performTask(String[] args) throws FileNotFoundException { ... throw new FileNotFoundException() }

Slide 42

Slide 42 text

Unchecked exceptions 42 void task() throws RuntimeException { ... }

Slide 43

Slide 43 text

Result 43 enum Result { case success(T) case failure(Error) }

Slide 44

Slide 44 text

44 func contentsOfFile( path: String) -> Result { return .success("") } func performTask() -> Result { return .failure(Err.some) } enum Result { case success(T) case failure(Error) }

Slide 45

Slide 45 text

Errors have types

Slide 46

Slide 46 text

EVEN MORE 
 POWERFUL TYPES

Slide 47

Slide 47 text

Array sort 1 6 2 8 3 4 1 2 3 4 6 8

Slide 48

Slide 48 text

Idris 48 insSort : Vect n elem -> Vect n elem

Slide 49

Slide 49 text

Dependent types 49 insSort : Vect n elem -> Vect n elem FUNC NAME ARGUMENT TYPE DEPENDENT TYPE ARGUMENT NAME RETURN TYPE

Slide 50

Slide 50 text

DEPENDENT TYPES 
 IN SWIFT?

Slide 51

Slide 51 text

1 ≠ 2 51 protocol Nat { init() } struct Zero: Nat {} protocol NonZero: Nat { associatedtype Predecessor: Nat }

Slide 52

Slide 52 text

52 protocol NonZero: Nat { associatedtype Predecessor: Nat } struct Successor: NonZero { typealias Predecessor = N } typealias One = Successor typealias Two = Successor typealias Three = Successor …

Slide 53

Slide 53 text

53 protocol BinaryOperation { associatedtype A: Nat associatedtype B: Nat } struct Successor: NonZero { typealias Predecessor = N }

Slide 54

Slide 54 text

54 struct EQ {} extension BinaryOperation where A == B { var r: EQ { return EQ() } } struct NEQ {} extension BinaryOperation { var r: NEQ { return NEQ() } }

Slide 55

Slide 55 text

55 struct Compare : BinaryOperation { typealias A = L typealias B = R } Compare().r //EQ Compare().r //NEQ

Slide 56

Slide 56 text

56 //struct NEQ {} //extension BinaryOperation { // var r: NEQ { return NEQ() } //} Compare().r //Compile time error

Slide 57

Slide 57 text

Not type dependent

Slide 58

Slide 58 text

BEN-G/VALIDATED 58 typealias LoggedInUser = Validated

Slide 59

Slide 59 text

TYPE DRIVEN

Slide 60

Slide 60 text

TDD RED -> GREEN -> REFACTOR

Slide 61

Slide 61 text

TypeDD TYPE -> DEFINE-> REFINE

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

Type Holes in Swift 68 func typeHole (_ description: String = "") -> T { fatalError("unfilled hole \(description)") }

Slide 69

Slide 69 text

› Types and type systems › Painless types › Swift type system is almost good › Type DD Summary

Slide 70

Slide 70 text

› Finite-state machine › Hindley-Milner algorithm › Curry-Howard isomorphism › Dependent types in Idris Even more

Slide 71

Slide 71 text

Попов Валерий Инженер-разработчик [email protected] @complexityclass