Leveraging Swift's Type System

Leveraging Swift's Type System

One of the most remarkable qualities of Swift, compared to Objective-C, is its powerful type system. Swift developers have quickly accustomed themselves to the benefits of safer, more expressive APIs.

However, many of us don’t leverage the type system as much as we could. Types can help us eliminate duplicate code, build APIs that are easy to comprehend and even verify a significant portion of our program’s behavior.

This talk will explore how we can leverage the power of Swift’s type system in three broad categories:

1. Code Sharing with Types, via Protocols & Generics
2. Program Verification with Types, including a brief discussion on Types vs. Tests
3. Type First Development

We will discuss how these ideas can be applied in practice by including examples from production apps with large code bases.
Throughout the talk we will also discuss concepts from languages with other type systems and see how they apply to Swift.
Hopefully this talk will inspire the audience to unleash the superpowers of types in their own programs.

De23af005c790b22f8ce4d201e6ca027?s=128

Benjamin Encz

August 24, 2016
Tweet

Transcript

  1. 1.

    Benjamin Encz @benjaminencz 1 — Leveraging Swift's Type System |

    @benjaminencz | 360iDev 2016, August 2016
  2. 2.

    Leveraging Swift's Type System 2 — Leveraging Swift's Type System

    | @benjaminencz | 360iDev 2016, August 2016
  3. 3.

    1. Why Types? 2. Correctness & Documentation via Types 3.

    Code Design with Types 3 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  4. 4.

    ! Margaret Hamilton with the Apollo 11 code listings /

    NASA P63SPOT3 CA BIT6 # IS THE LR ANTENNA IN POSITION 1 YET EXTEND RAND CHAN33 EXTEND BZF P63SPOT4 # BRANCH IF ANTENNA ALREADY IN POSITION 1 CAF CODE500 # ASTRONAUT: PLEASE CRANK THE TC BANKCALL # SILLY THING AROUND CADR GOPERF1 TCF GOTOP00H # TERMINATE TCF P63SPOT3 # PROCEED SEE IF HE'S LYING P63SPOT4 TC BANKCALL # ENTER INITIALIZE LANDING RADAR CADR SETPOS1 TC POSTJUMP # OFF TO SEE THE WIZARD ... CADR BURNBABY 4 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  5. 6.

    int a = 2; int b = a; // Copy

    n bytes into a new stack variable ✅ 6 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  6. 7.

    NSNumber *a = @(2); NSString *c = a; // Incompatible

    pointer types ⚠ [c viewDidLoad]; // No visibile interface declares selector ❌ 7 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  7. 8.

    NSString *name = nil; NSDictionary *broken = @{@"test": name}; //

    Nil crash! ! 8 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  8. 9.

    For Each Type a Type System Defines... 1. ... a

    valid set of values 2. ... a valid set of operations 3. ... a representation 9 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  9. 10.
  10. 11.
  11. 12.
  12. 13.

    (result: NSData?, error: NSError?) // 4 possible combinations ! 13

    — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  13. 14.

    (result: NSData?, error: NSError?) // 4 possible combinations ! (result:

    Result<Data, NetworkError>) // 2 possible combinations 14 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  14. 15.

    switch result { case let .success(value): // use success value

    case let .failure(error): // handle error } 15 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  15. 16.

    public enum Optional<Wrapped> { case none case some(Wrapped) } public

    enum Result<T, Error: Swift.Error> { case success(T) case failure(Error) } 16 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  16. 17.

    Enums with Associated Values1 ! 1 Formally known as tagged

    unions 17 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  17. 20.

    // Document semantics of types typealias Address = String typealias

    Email = String struct Person { // ... let email: Email let address: Address } 20 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  18. 21.

    // Document & validate semantics struct Address { let value:

    String init(addressString: String) throws { // ... } } 21 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  19. 22.

    github.com/Ben-G/Validated typealias Email = Validated<String, EmailValidator> let maybeEmail = Email("test@test.com")

    22 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  20. 23.

    Typealias ! Wrapper Types !! 23 — Leveraging Swift's Type

    System | @benjaminencz | 360iDev 2016, August 2016
  21. 25.

    struct ObjectUid<!> { let value: String } 25 — Leveraging

    Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  22. 26.

    func currentUserUid() -> ObjectUid<User> func annotationByUid(annotationUid: ObjectUid<Annotation>) -> Annotation func

    annotationsForUser(userUid: ObjectUid<User>) -> [Annotation] 26 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  23. 27.

    Type Case Study: Modelling JSON Encodable? 27 — Leveraging Swift's

    Type System | @benjaminencz | 360iDev 2016, August 2016
  24. 30.

    enum JsonRoot { case dictionary(JsonDictionary) case array(JsonArray) } 30 —

    Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  25. 31.

    protocol JsonValue {} enum JsonRoot: JsonValue { case dictionary(JsonDictionary) case

    array(JsonArray) } extension NSString : JsonValue { } extension NSNumber : JsonValue { } 31 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  26. 32.

    typealias JsonDictionary = [String : JsonValue?] typealias JsonArray = [JsonValue]

    32 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  27. 34.

    protocol JsonValue {} typealias JsonDictionary = [String : JsonValue?] typealias

    JsonArray = [JsonValue] enum JsonRoot: JsonValue { case dictionary(JsonDictionary) case array(JsonArray) } extension NSString : JsonValue { } extension NSNumber : JsonValue { } func toJsonString(json: JsonRoot) -> String 34 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  28. 36.

    Protocols ! Generics 36 — Leveraging Swift's Type System |

    @benjaminencz | 360iDev 2016, August 2016
  29. 37.
  30. 40.

    protocol Downloadable { static var endpoint: URL { get }

    } protocol Decodable { init(data: Data) throws } protocol Cachable { static var cachingDuration: TimeInterval { get } } 40 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  31. 41.

    final class Downloader<T: Downloadable> { func download(identifier: String) throws ->

    Data { let targetUrl = T.self.endpoint.appendingPathComponent(identifier) // .. return data } } 41 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  32. 42.

    final class Downloader<T: Downloadable> { func download(identifier: String) throws ->

    Data { let targetUrl = T.self.endpoint.appendingPathComponent(identifier) // ... // Check if this type is cachable if let type = T.self as? Cachable.Type, let cachedResult = cache[targetUrl] { // Attempt to fetch data from cache } // Otherwise download & cache result if type is cachable if T.self is Cachable.Type { cache[targetUrl] = (Date(), data) } return data } } 42 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  33. 43.

    extension Downloader where T: Decodable { func download(identifier: String) throws

    -> T { let result: Data = try self.download(identifier: identifier) return try T(data: result) } } 43 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  34. 44.

    extension Photo: Downloadable { static let endpoint = URL(string: "https://photos.example.com")!

    } extension Photo: Cachable { static let cachingDuration: TimeInterval = 3600 } extension Photo: Decodable { static func decode(data: Data) throws -> Photo { // ... } } 44 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  35. 45.

    let downloader: Downloader<Photo> = Downloader() let photo: Photo = try

    downloader.download(identifier: "hawaii2") 45 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  36. 46.

    Protocols ! Generics " Safe Dynamic Type Checking ! Constrained

    Extensions ! 46 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  37. 48.

    ! Types Document ! Types Enable Correctness Checks ! Generics

    Offer Alternative to Subtyping ! Concepts: Optional, Result, Enums with Associated Values, Typealias, Wrapper Types, Phantom Types, Safe Dynamic Type Checking, Constrained Extensions 48 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  38. 49.

    Thank you! bit.ly/types360 @benjaminencz Thanks a lot to Jaden Geller,

    Russ Bishop and Morgan Chen for feedback on this talk. 49 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016
  39. 50.

    Related Talks: → Correct Behavior Through Type Safety (Justin Spahr-Summers)

    → Type Driven Development in Swift (Johannas Weiß) → Protocol Oriented Programming in Swift (WWDC 2015) 50 — Leveraging Swift's Type System | @benjaminencz | 360iDev 2016, August 2016