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

Flexible Code for Generic Collections

Nate Cook
November 07, 2016

Flexible Code for Generic Collections

Presented at Swift Summit on 11/7/2016

Nate Cook

November 07, 2016
Tweet

More Decks by Nate Cook

Other Decks in Programming

Transcript

  1. struct Brick { let color: UIColor let size: (w: Int,

    h: Int) } let redSquare = Brick(color: .red, size: (2, 2)) let orangeSquare = Brick(color: .orange, size: (2, 2))
  2. struct Brick { let color: UIColor let size: (w: Int,

    h: Int) } let redSquare = let orangeSquare =
  3. struct Brick { let color: UIColor let size: (w: Int,

    h: Int) } let bricks = [ , , , , , , ]
  4. func createBrickPDF(_ bricks: [Brick]) -> Data { let result =

    NSMutableData() // prepare PDF context for brick in bricks { // generate PDF data } return result as Data }
  5. let bricks = [ , , , , , ,

    ] let pdfData = createBrickPDF(bricks) // Success!
  6. !"#

  7. let bricks = [ , , , , , ,

    ] let firstFiveBricks = bricks.prefix(5)
  8. let bricks = [ , , , , , ,

    ] let firstFiveBricks = bricks.prefix(5) Wow such swift so declarativ wow
  9. let bricks = [ , , , , , ,

    ] let firstFiveBricks = bricks.prefix(5) let pdfData = createBrickPDF(firstFiveBricks) Cannot convert value of type ‘ArraySlice<Brick>’ to expected argument type ‘[Brick]’ !
  10. $%&

  11. let bricks = [ , , , , , ,

    ] let firstFiveBricks = bricks.prefix(5) let pdfData = createBrickPDF(firstFiveBricks) Cannot convert value of type ‘ArraySlice<Brick>’ to expected argument type ‘[Brick]’ !
  12. , , , , , ] ks = bricks.prefix(5) ateBrickPDF(firstFiveBricks)

    convert value of type ‘ArraySlice<Brick>’ to expected argum
  13. let bricks = [ , , , , , ,

    ] let firstFiveBricks = bricks.prefix(5) let pdfData = createBrickPDF(firstFiveBricks) Cannot convert value of type ‘ArraySlice<Brick>’ to expected argument type ‘[Brick]’ !
  14. let bricks = [ , , , , , ,

    ] let firstFiveBricks = bricks.prefix(5) let pdfData = createBrickPDF(Array(firstFiveBricks))
  15. let bricks = [ , , , , , ,

    ] let firstFiveBricks = bricks.prefix(5) let pdfData = createBrickPDF(Array(firstFiveBricks)) // '☕
  16. let middleBricks = bricks[2..<5] // ArraySlice<Brick> let lastThreeBricks = bricks.suffix(3)

    // ArraySlice<Brick> let bricksAfterFirstTwo = bricks.dropFirst(2) // ArraySlice<Brick>
  17. let backwardsBricks = bricks.reversed() // ReversedRandomAccessCollection<[Brick]> let squareBrickColors = bricks.lazy

    .filter { $0.isSquare } .map { $0.color } // LazyMapBidirectionalCollection // <LazyFilterBidirectionalCollection<[Brick]>, UIColor>
  18. LazySequence MutableBidirectionalSlice LazyBidirectionalCollection ReversedRandomAccessCollection EnumeratedSequence FlattenCollection LazyMapSequence LazyFilterBidirectionalCollection AnyBidirectionalCollection MutableRangeReplaceableBidirectionalSlice

    LazyMapBidirectionalCollection LazyCollection BidirectionalSlice AnyRandomAccessCollection ArraySlice FlattenBidirectionalCollection Zip2Sequence MutableSlice AnyCollection AnySequence RangeReplaceableBidirectionalSlice JoinedSequence LazyMapRandomAccessCollection LazyFilterCollection LazyMapCollection MutableRangeReplaceableRandomAccessSlice RandomAccessSlice RangeReplaceableSlice LazyFilterSequence LazyRandomAccessCollection MutableRangeReplaceableSlice RangeReplaceableRandomAccessSlice FlattenSequence ReversedCollection MutableRandomAccessSlice
  19. LazySequence MutableBidirectionalSlice LazyBidirectionalCollection ReversedRandomAccessCollection EnumeratedSequence FlattenCollection LazyMapSequence LazyFilterBidirectionalCollection AnyBidirectionalCollection MutableRangeReplaceableBidirectionalSlice

    LazyMapBidirectionalCollection LazyCollection BidirectionalSlice AnyRandomAccessCollection ArraySlice FlattenBidirectionalCollection Zip2Sequence MutableSlice AnyCollection AnySequence RangeReplaceableBidirectionalSlice JoinedSequence LazyMapRandomAccessCollection LazyFilterCollection LazyMapCollection MutableRangeReplaceableRandomAccessSlice RandomAccessSlice RangeReplaceableSlice LazyFilterSequence LazyRandomAccessCollection MutableRangeReplaceableSlice RangeReplaceableRandomAccessSlice FlattenSequence ReversedCollection MutableRandomAccessSlice
  20. Sequence protocol for brick in bricks.prefix(5) { print(brick) } //

    , , , , for number in 1..<10 { print(number) } // 1, 2, 3, 4, 5, 6, 7, 8, 9
  21. Sequence protocol bricks.contains(where: { $0.color == .blue }) // true

    bricks.first(where: { $0.color == .blue }) // Optional( ) [2, 4, 5, 3, 7, 2, 9].max() // Optional(9)
  22. Sequence protocol (1..<10).map({ "\($0)" }) // ["1", "2", "3", "4",

    "5", "6", "7", "8", "9"] (1..<10).filter({ $0 % 2 == 0 }) // [2, 4, 6, 8] (1..<10).reduce(0, +) // 45
  23. Collection protocol bricks[1] // if let i = bricks.index(where: {

    $0.color == .blue }) { print(i, bricks[i]) } // 4, bricks.count // 7
  24. Iterator of a sequence for brick in bricks { print(brick)

    } // , , , , , , var iterator = bricks.makeIterator() while let brick = iterator.next() { print(brick) } // , , , , , ,
  25. func createBrickPDF(_ bricks: [Brick]) -> Data { let result =

    NSMutableData() // prepare PDF context for brick in bricks { // generate PDF data } return result as Data }
  26. func createBrickPDF(_ bricks: [Brick]) -> Data { let result =

    NSMutableData() // prepare PDF context for brick in bricks { // generate PDF data } return result as Data }
  27. func createBrickPDF<S: Sequence>(_ bricks: S) -> Data where S.Iterator.Element ==

    Brick { let result = NSMutableData() // prepare PDF context for brick in bricks { // generate PDF data } return result as Data }
  28. func createBrickPDF<S: Sequence>(_ bricks: S) -> Data where S.Iterator.Element ==

    Brick { let result = NSMutableData() // prepare PDF context for brick in bricks { // generate PDF data } return result as Data }
  29. func createBrickPDF<S: Sequence>(_ bricks: S) -> Data where S.Iterator.Element ==

    Brick { let result = NSMutableData() // prepare PDF context for brick in bricks { // generate PDF data } return result as Data }
  30. Value of type ’S’ has no member ‘count’ ! func

    createBrickPDF<S: Sequence>(_ bricks: S) -> Data where S.Iterator.Element == Brick { let result = NSMutableData() // prepare PDF context let renderer = BrickPDFRenderer(count: bricks.count) for brick in bricks { // generate PDF data } return result as Data }
  31. func createBrickPDF<C: Collection>(_ bricks: C) -> Data where C.Iterator.Element ==

    Brick { let result = NSMutableData() // prepare PDF context let renderer = BrickPDFRenderer(count: bricks.count) for brick in bricks { // generate PDF data } return result as Data }
  32. func createBrickPDF<S: Sequence>(_ bricks: S) -> Data where S.Iterator.Element ==

    Brick { ... } let bricks = [ , , , , , , ] let firstFiveBricks = bricks.prefix(5) let pdfData = createBrickPDF(firstFiveBricks) // Success!!
  33. Generic type class BrickRenderer<C: Collection> where C.Iterator.Element == Brick {

    let bricks: C init(_ bricks: C) { self.bricks = bricks } }
  34. Type erasure class BrickRenderer { let bricks: AnyCollection<Brick> init(_ bricks:

    AnyCollection<Brick>) { self.bricks = bricks } } let renderer = BrickRenderer(AnyCollection(bricks)) let renderer = BrickRenderer(AnyCollection(firstFiveBricks))
  35. extension Array where Element == Bool { func allTrue() ->

    Bool { for x in self { if !x { return false } } return true } }
  36. extension Array where Element == Bool { func allTrue() ->

    Bool { for x in self { if !x { return false } } return true } } Same-type requirement makes generic parameter 'Element' non-generic !
  37. extension Sequence where Iterator.Element == Bool { func allTrue() ->

    Bool { for x in self { if !x { return false } } return true } }
  38. func createBrickPDF<S: Sequence>(_ bricks: S) -> Data where S.Iterator.Element ==

    Brick Swift 3 func createBrickPDF<S: SequenceType where S.Generator.Element == Brick> (_ bricks: S) -> NSData Swift 2