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

Swifty?

 Swifty?

Presented at Swift London.

Swift is young, and we're still figuring out what Swifty code looks like. I'll take a look at emerging idioms and patterns, and how Swift 3 will mix things up (again).

94fc7b58c03a0650fe1e8d78140bd451?s=128

Dan Cutting

July 05, 2016
Tweet

Transcript

  1. Dan Cutting @dcutting cutting.io Swifty?

  2. Singletons! 503,000 359,000 "swift singleton" "swift singleton bad"

  3. None
  4. var report = getSpyReport() report = encrypt(message: report) transmit(message: report)

    !
  5. var report = getSpyReport() //report = encrypt(message: report) transmit(message: report)

    !
  6. enum Encrypted {} // Phantom types! enum Decrypted {} func

    transmit(message: Secret<Encrypted>) { // ... } struct Secret<T> { let value: String }
  7. Cannot convert value of type 'Secret<Decrypted>' to expected argument type

    'Secret<Encrypted>' func getSpyReport() -> Secret<Decrypted> { return Secret(value: "!") } let report = getSpyReport() transmit(message: report)
  8. func encrypt(message: Secret<Decrypted>) -> Secret<Encrypted> { let encrypted = rot13(message:

    message.value) return Secret(value: encrypted) } let report = getSpyReport() let encrypted = encrypt(message: report) transmit(message: encrypted)
  9. None
  10. struct Array { // ... }

  11. class Warren { enum Mick { struct Jim { static

    let rock = true } } } Warren.Mick.Jim.rock
  12. struct Array { // ... }

  13. enum MyProject { struct Array { // ... } }

    let myArray = MyProject.Array()
  14. enum Components { enum List {} enum Search {} enum

    Detail {} } extension Components.List { class Service { // ... } } let listService = Components.List.Service()
  15. None
  16. Building blocks that add behaviour to types

  17. mixin CanMove { var position = CGPoint.zero var speed =

    CGVector.zero func move(for timeSlice: CGFloat) { position = position + timeSlice * speed } } struct Player: CanMove, HasHealth {} struct Enemy: CanMove, HasMagic {}
  18. struct CanMoveMixin { var position = CGPoint.zero var speed =

    CGVector.zero mutating func move(for timeSlice: CGFloat) { position = position + timeSlice * speed } } mixin CanMove { var position = CGPoint.zero var speed = CGVector.zero func move(for timeSlice: CGFloat) { position = position + timeSlice * speed } }
  19. protocol CanMove { mutating func move(for timeSlice: CGFloat) } mixin

    CanMove { var position = CGPoint.zero var speed = CGVector.zero func move(for timeSlice: CGFloat) { position = position + timeSlice * speed } }
  20. struct Player: CanMove { var canMoveMixin = CanMoveMixin() mutating func

    move(for timeSlice: CGFloat) { canMoveMixin.move(for: timeSlice) } }
  21. struct Enemy: CanMove { var canMoveMixin = CanMoveMixin() mutating func

    move(for timeSlice: CGFloat) { canMoveMixin.move(for: timeSlice) } }
  22. protocol CanMove { mutating func move(for timeSlice: CGFloat) } var

    canMoveMixin: CanMoveMixin { get set } extension CanMove { mutating func move(for timeSlice: CGFloat) { canMoveMixin.move(for: timeSlice) } }
  23. struct Player: CanMove, HasHealth { var canMoveMixin = CanMoveMixin() var

    hasHealthMixin = HasHealthMixin() } struct Enemy: CanMove, HasMagic { var canMoveMixin = CanMoveMixin() var hasMagicMixin = HasMagicMixin() } struct Player: CanMove, HasHealth {} struct Enemy: CanMove, HasMagic {}
  24. swift

  25. is wtf?

  26. • SE-0007: Remove C-style for-loops with conditions and incrementers •

    SE-0016: Adding initializers to Int and UInt to convert from UnsafePointer and UnsafeMutablePointer • SE-0019: Swift Testing • SE-0023: API Design Guidelines • SE-0028: Modernizing Swift's Debugging Identifiers (__FILE__, etc) • SE-0029: Remove implicit tuple splat behavior from function applications • SE-0031: Adjusting inout Declarations for Type Decoration • SE-0034: Disambiguating Line Control Statements from Debugging Identifiers • SE-0037: Clarify interaction between comments & operators • SE-0039: Modernizing Playground Literals • SE-0040: Replacing Equal Signs with Colons For Attribute Arguments • SE-0043: Declare variables in 'case' labels with multiple patterns • SE-0046: Establish consistent label behavior across all parameters including first labels • SE-0049: Move @noescape and @autoclosure to be type attributes • SE-0053: Remove explicit use of let from Function Parameters • SE-0054: Abolish ImplicitlyUnwrappedOptional type • SE-0055: Make unsafe pointer nullability explicit using Optional • SE-0059: Update API Naming Guidelines and Rewrite Set APIs Accordingly • SE-0061: Add Generic Result and Error Handling to autoreleasepool() • SE-0065: A New Model For Collections and Indices • SE-0069: Mutability and Foundation Value Types • SE-0070: Make Optional Requirements Objective-C-only • SE-0071: Allow (most) keywords in member references • SE-0072: Fully eliminate implicit bridging conversions from Swift • SE-0025: Scoped Access Level • SE-0032: Add find method to SequenceType • SE-0033: Import Objective-C Constants as Swift Types • SE-0035: Limiting inout capture to @noescape contexts • SE-0036: Requiring Leading Dot Prefixes for Enum Instance Member Impleme • SE-0038: Package Manager C Language Target Support • SE-0042: Flattening the function type of unapplied method references • SE-0044: Import as Member • SE-0045: Add scan, prefix(while:), drop(while:), and iterate to the stdlib • SE-0047: Defaulting non-Void functions so they warn on unused results • SE-0048: Generic Type Aliases • SE-0052: Change IteratorType post-nil guarantee • SE-0057: Importing Objective-C Lightweight Generics • SE-0062: Referencing Objective-C key-paths • SE-0063: SwiftPM System Module Search Paths • SE-0064: Referencing the Objective-C selector of property getters and setters • SE-0066: Standardize function type argument syntax to require parentheses • SE-0067: Enhanced Floating Point Protocols • SE-0068: Expanding Swift Self to class members and value types
  27. let var

  28. var url = NSURL(fileURLWithPath: "/dev") url = url.URLByAppendingPathComponent("/null")

  29. var url = URL(fileURLWithPath: "/dev") try! url.appendPathComponent("/null")

  30. let url = URL(fileURLWithPath: "/dev") try! url.appendPathComponent("/null")

  31. public class Counter { private var value: Int = 0

    public func increment() { value += 1 } } let counter = Counter() counter.increment() counter.value = 99 Scoped Access
  32. func apply(value: Int, f: @noescape (Int) -> (Int)) -> Int

    { return f(value) }. let _ = apply(value: 7) { $0 * 2 }. @noescape
  33. func apply(value: Int, f: (Int) -> (Int)) -> Int {

    return f(value) }. let _ = apply(value: 7) { $0 * 2 }. @noescape
  34. protocol Drama {} protocol Comedy {} struct BreakfastClub: Drama, Comedy

    {} let movie: Drama & Comedy = BreakfastClub() let movie: protocol<Drama, Comedy> = BreakfastClub() func watch<T: Drama & Comedy>(dramedy: T) { // ... } Protocols
  35. for loops! for (var i = 0; i < 10;

    i++) { print(i) } for i in (0..<10) { print(i) }
  36. for x in sequence(first: 1, next: { $0 * 2

    }) { print(x) } .prefix(4)
  37. struct Fib { var current: Int var next: Int }

    let f = Fib(current: 0, next: 1) let s = sequence(state: f) { (f: inout Fib) -> Int? in return f.current } defer { } let sum = f.current + f.next f.current = f.next f.next = sum
  38. @dcutting