Slide 1

Slide 1 text

Flexible Code for Generic Collections Nate Cook @nnnnnnnn

Slide 2

Slide 2 text

The standard library collections system (Nate’s favorite part of Swift)

Slide 3

Slide 3 text

Protocols in Objective-C

Slide 4

Slide 4 text

Protocols in Swift

Slide 5

Slide 5 text

1. A problem 2.Why it happens 3.What to do about it

Slide 6

Slide 6 text

struct Brick { let color: UIColor let size: (w: Int, h: Int) }

Slide 7

Slide 7 text

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))

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

struct Brick { let color: UIColor let size: (w: Int, h: Int) } let bricks = [ , , , , , , ]

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

let bricks = [ , , , , , , ] let pdfData = createBrickPDF(bricks) // Success!

Slide 12

Slide 12 text

!"#

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

$%&

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

, , , , , ] ks = bricks.prefix(5) ateBrickPDF(firstFiveBricks) convert value of type ‘ArraySlice’ to expected argum

Slide 19

Slide 19 text

DF(firstFiveBrick type ‘ArraySlice’ to exp

Slide 20

Slide 20 text

(˽°□°)˽ Ɨ ʇɟıʍs

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

let bricks = [ , , , , , , ] let firstFiveBricks = bricks.prefix(5) let pdfData = createBrickPDF(Array(firstFiveBricks)) // '☕

Slide 24

Slide 24 text

1. A problem 2.Why it happens 3.What to do about it

Slide 25

Slide 25 text

let middleBricks = bricks[2..<5] // ArraySlice let lastThreeBricks = bricks.suffix(3) // ArraySlice let bricksAfterFirstTwo = bricks.dropFirst(2) // ArraySlice

Slide 26

Slide 26 text

let backwardsBricks = bricks.reversed() // ReversedRandomAccessCollection<[Brick]> let squareBrickColors = bricks.lazy .filter { $0.isSquare } .map { $0.color } // LazyMapBidirectionalCollection // , UIColor>

Slide 27

Slide 27 text

Collection wrappers

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Brought to you by Brick-o-Vision™

Slide 31

Slide 31 text

let bricks = [ , , , , , , ]

Slide 32

Slide 32 text

let bricksCopy = Array(bricks.prefix(5))

Slide 33

Slide 33 text

let firstFiveBricks = bricks.prefix(5)

Slide 34

Slide 34 text

1. A problem 2.Why it happens 3.What to do about it

Slide 35

Slide 35 text

Collection protocols

Slide 36

Slide 36 text

Sequence Collection MutableCollection RangeReplaceableCollection BidirectionalCollection Array ArraySlice RandomAccessCollection

Slide 37

Slide 37 text

Sequence Collection MutableCollection RangeReplaceableCollection BidirectionalCollection Array ArraySlice RandomAccessCollection

Slide 38

Slide 38 text

A series of values we access one at a time

Slide 39

Slide 39 text

Sequence protocol for brick in bricks { print(brick) } // , , , , , ,

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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)

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

Sequence Collection MutableCollection RangeReplaceableCollection BidirectionalCollection Array ArraySlice RandomAccessCollection

Slide 44

Slide 44 text

Collection protocol bricks[1] // if let i = bricks.index(where: { $0.color == .blue }) { print(i, bricks[i]) } // 4, bricks.count // 7

Slide 45

Slide 45 text

Sequence Collection MutableCollection RangeReplaceableCollection BidirectionalCollection Array ArraySlice RandomAccessCollection

Slide 46

Slide 46 text

Sequence Collection MutableCollection RangeReplaceableCollection BidirectionalCollection Array ArraySlice RandomAccessCollection IteratorProtocol

Slide 47

Slide 47 text

Iterator of a sequence for brick in bricks { print(brick) } // , , , , , ,

Slide 48

Slide 48 text

Iterator of a sequence for brick in bricks { print(brick) } // , , , , , , var iterator = bricks.makeIterator() while let brick = iterator.next() { print(brick) } // , , , , , ,

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

func createBrickPDF(_ 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 }

Slide 52

Slide 52 text

func createBrickPDF(_ 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 }

Slide 53

Slide 53 text

func createBrickPDF(_ 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 }

Slide 54

Slide 54 text

Value of type ’S’ has no member ‘count’ ! func createBrickPDF(_ 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 }

Slide 55

Slide 55 text

func createBrickPDF(_ 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 }

Slide 56

Slide 56 text

func createBrickPDF(_ bricks: S) -> Data where S.Iterator.Element == Brick { ... } let bricks = [ , , , , , , ] let firstFiveBricks = bricks.prefix(5) let pdfData = createBrickPDF(firstFiveBricks) // Success!!

Slide 57

Slide 57 text

!"#❤*✨!" ❤*✨!"#❤* ✨!"#❤*✨! "#❤*✨!"#

Slide 58

Slide 58 text

Storing generic collections

Slide 59

Slide 59 text

Generic type class BrickRenderer where C.Iterator.Element == Brick { let bricks: C init(_ bricks: C) { self.bricks = bricks } }

Slide 60

Slide 60 text

Type erasure class BrickRenderer { let bricks: AnyCollection init(_ bricks: AnyCollection) { self.bricks = bricks } }

Slide 61

Slide 61 text

Type erasure class BrickRenderer { let bricks: AnyCollection init(_ bricks: AnyCollection) { self.bricks = bricks } } let renderer = BrickRenderer(AnyCollection(bricks)) let renderer = BrickRenderer(AnyCollection(firstFiveBricks))

Slide 62

Slide 62 text

Type-specific extensions

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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 !

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

Syntax & Naming

Slide 67

Slide 67 text

func createBrickPDF(_ bricks: S) -> Data where S.Iterator.Element == Brick Swift 3 func createBrickPDF (_ bricks: S) -> NSData Swift 2

Slide 68

Slide 68 text

Thanks! "@" + repeatElement("n", count: 8).joined()