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

Ready for the future

Ready for the future

Swift is brand spanking new. How can we possibly be expected to write idiomatic code? On the other hand, Objective-C has been around for more than thirty years. We know what it looks like and feels like. The Objective-C of our iOS youth is very different than today’s Objective-C. Seen in this light, Swift is more evolutionary than you might think. In this talk we’ll look at Swift code in the light of the code of Objective-C and other languages that have come before it.

Daniel Steinberg http://dimsumthinking.com

do{iOS} conference

November 09, 2015
Tweet

More Decks by do{iOS} conference

Other Decks in Programming

Transcript

  1. Handwritten Slides?

    View full-size slide

  2. Boring Handwritten
    Slides

    View full-size slide

  3. This Talk Sucks

    View full-size slide

  4. I'm Already
    nodding off

    View full-size slide

  5. Not Even
    Speaker
    Colleagues
    Everyone
    Parents

    View full-size slide

  6. Eugenia Cheng: "Cakes, Custard + Category Theory"

    View full-size slide

  7. Eugenia Cheng: "Cakes, Custard + Category Theory"

    View full-size slide

  8. Eugenia Cheng: "Cakes, Custard + Category Theory"
    I hope this talk isn't about
    Monads and Functors.

    View full-size slide

  9. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan

    View full-size slide

  10. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan

    View full-size slide

  11. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan

    View full-size slide

  12. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan

    View full-size slide

  13. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan
    Béchamel is one of
    the mother sauces

    View full-size slide

  14. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan
    Bechamel Sauce
    » Butter
    » Flour
    » Milk
    » Salt and Pepper

    View full-size slide

  15. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan
    Bechamel Sauce
    » Butter
    » Flour
    » Milk
    » Salt and Pepper

    View full-size slide

  16. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan
    Bechamel Sauce
    » Butter
    » Flour
    » Milk
    » Salt and Pepper
    Context matters

    View full-size slide

  17. Context matters

    View full-size slide

  18. Context matters

    View full-size slide

  19. An Obj-C example

    View full-size slide

  20. An Obj-C example

    View full-size slide

  21. An Obj-C example

    View full-size slide

  22. - (NSTimeInterval)elapsed Time {
    NSDate *now = [[NSDate alloc] init];
    NSTimeInterval elapsed Time = [now timeIntervalS inceDate:self.startTime];
    return elapsedTime;
    }

    View full-size slide

  23. - (NSTimeInterval)elapsed Time {
    NSDate *now = [[NSDate alloc] init];
    NSTimeInterval elapsed Time = [now timeIntervalS inceDate:self.startTime];
    return elapsedTime;
    }

    View full-size slide

  24. - (NSTimeInterval)elapsed Time {
    NSDate *now = [[NSDate alloc] init];
    NSTimeInterval elapsed Time = [now timeIntervalS inceDate:self.startTime];
    return elapsedTime;
    }

    View full-size slide

  25. - (NSTimeInterval)elapsed Time {
    NSDate *now = [[NSDate alloc] init];
    NSTimeInterval elapsed Time = [now timeIntervalS inceDate:self.startTime];
    return elapsedTime;
    }

    View full-size slide

  26. - (NSTimeInterval)elapsed Time {
    NSDate *now = [[NSDate alloc] init];
    NSTimeInterval elapsed Time = [now timeIntervalS inceDate:self.startTime];
    return elapsedTime;
    }

    View full-size slide

  27. - (NSTimeInterval)elapsed Time {
    return [self.startTime timeIntervalSinceNow];
    }

    View full-size slide

  28. - (NSTimeInterval)elapsed Time {
    return [self.startTime timeIntervalSinceNow];
    }

    View full-size slide

  29. - (NSTimeInterval)elapsed Time {
    return -[self.startTime timeIntervalSinceNow];
    }

    View full-size slide

  30. - (NSTimeInterval)elapsed Time {
    return -[self.startTime timeIntervalSinceNow];
    }

    View full-size slide

  31. - (NSTimeInterval)elapsed Time {
    return [self.startTime timeIntervalUntilNow];
    }

    View full-size slide

  32. #import
    @interface NSDate (TimerCalculations)
    - (NSTimeInterval)timeIntervalUntilNow;
    @end

    View full-size slide

  33. #import
    @interface NSDate (TimerCalculations)
    - (NSTimeInterval)timeIntervalUntilNow;
    @end

    View full-size slide

  34. #import "NSDate+TimerCalculations.h"
    @implementation NSDate (TimerCalculations)
    - (NSTimeInterval) timeIntervalUntilNow {
    return - [self timeIntervalSinceNow];
    }
    @end

    View full-size slide

  35. #import "NSDate+TimerCalculations.h"
    @implementation NSDate (TimerCalculations)
    - (NSTimeInterval) timeIntervalUntilNow {
    return - [self timeIntervalSinceNow];
    }
    @end

    View full-size slide

  36. #import "NSDate+TimerCalculations.h"
    @implementation NSDate (TimerCalculations)
    - (NSTimeInterval) timeIntervalUntilNow {
    return - [self timeIntervalSinceNow];
    }
    @end

    View full-size slide

  37. #import "NSDate+TimerCalculations.h"
    @implementation NSDate (TimerCalculations)
    - (NSTimeInterval)dst_timeIntervalUntilNow {
    return - [self timeIntervalSinceNow];
    }
    @end

    View full-size slide

  38. - (NSTimeInterval)elapsedTime {
    return [self.startTime timeInterval UntilNow];
    }

    View full-size slide

  39. - (NSTimeInterval)elapsedTime {
    return startTime.timeIntervalUntilNow
    }

    View full-size slide

  40. - (NSTimeInterval)elapsedTime {
    return startTime.timeIntervalUntilNow
    }
    Exactly

    View full-size slide

  41. - (NSTimeInterval)elapsedTime {
    return startTime.timeIntervalUntilNow
    }
    Let's get to
    some swift

    View full-size slide

  42. - (NSTimeInterval)elapsedTime {
    return startTime.timeIntervalUntilNow
    }
    Show me some
    clever
    unreadable code

    View full-size slide

  43. - (NSTimeInterval)elapsedTime {
    return startTime.timeIntervalUntilNow
    }
    Let's see some
    Generics and
    Custom operators

    View full-size slide

  44. The model in Swift

    View full-size slide

  45. struct Timer {
    let startTime = NSDate()
    var elapsedTime: NSTimeInterval {
    return startTime.timeIntervalUntilNow
    }
    }

    View full-size slide

  46. struct Timer {
    let startTime = NSDate()
    var elapsedTime: NSTimeInterval {
    return startTime.timeIntervalUntilNow
    }
    }

    View full-size slide

  47. struct Timer {
    let startTime = NSDate()
    var elapsedTime: NSTimeInterval {
    return startTime.timeIntervalUntilNow
    }
    }

    View full-size slide

  48. struct Timer {
    let startTime = NSDate()
    var elapsedTime: NSTimeInterval {
    return startTime.timeIntervalUntilNow
    }
    }

    View full-size slide

  49. }
    }
    extension NSDate {
    var timeIntervalUntilNow: NSTimeInterval {
    return -timeIntervalSinceNow
    }
    }

    View full-size slide

  50. extension NSDate {
    var timeIntervalUntilNow: NSTimeInterval {
    return -timeIntervalSinceNow
    }
    }

    View full-size slide

  51. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan
    Bechamel Sauce
    » Butter
    » Flour
    » Milk
    » Salt and Pepper

    View full-size slide

  52. UmmM, Daniel

    View full-size slide

  53. You Started
    with Obj-C

    View full-size slide

  54. And converted
    it to Swift

    View full-size slide

  55. What about
    Real Swift

    View full-size slide

  56. Show me Map,
    Filter, reduce!

    View full-size slide

  57. Silly Example

    View full-size slide

  58. import GameplayKit
    struct AppSales: SequenceType {
    let numberOfDays: Int
    let randomDistribution = GKGaussianDistribution(lowestValue: 0, highestValue: 10)
    func generate() -> Any Generator {
    var count = 0
    return anyGenerator({
    if count++ < self .numberOfDays {
    return self .randomDistribution.nextInt()
    } else {
    return nil
    }
    })
    }
    }

    View full-size slide

  59. import GameplayKit
    struct AppSales: SequenceType {
    let numberOfDays: Int
    let randomDistribution = GKGaussianDistribution(lowestValue: 0, highestValue: 10)
    func generate() -> Any Generator {
    var count = 0
    return anyGenerator({
    if count++ < self .numberOfDays {
    return self .randomDistribution.nextInt()
    } else {
    return nil
    }
    })
    }
    }

    View full-size slide

  60. import GameplayKit
    struct AppSales: SequenceType {
    let numberOfDays: Int
    let randomDistribution = GKGaussianDistribution(lowestValue: 0, highestValue: 10)
    func generate() -> Any Generator {
    var count = 0
    return anyGenerator({
    if count++ < self .numberOfDays {
    return self .randomDistribution.nextInt()
    } else {
    return nil
    }
    })
    }
    }

    View full-size slide

  61. import GameplayKit
    struct AppSales: SequenceType {
    let numberOfDays: Int
    let randomDistribution = GKGaussianDistribution(lowestValue: 0, highestValue: 10)
    func generate() -> Any Generator {
    var count = 0
    return anyGenerator({
    if count++ < self .numberOfDays {
    return self .randomDistribution.nextInt()
    } else {
    return nil
    }
    })
    }
    }

    View full-size slide

  62. import GameplayKit
    struct AppSales: SequenceType {
    let numberOfDays: Int
    let randomDistribution = GKGaussianDistribution(lowestValue: 0, highestValue: 10)
    func generate() -> Any Generator {
    var count = 0
    return anyGenerator({
    if count++ < self .numberOfDays {
    return self .randomDistribution.nextInt()
    } else {
    return nil
    }
    })
    }
    }

    View full-size slide

  63. import GameplayKit
    struct AppSales: SequenceType {
    let numberOfDays: Int
    let randomDistribution = GKGaussianDistribution(lowestValue: 0, highestValue: 10)
    func generate() -> Any Generator {
    var count = 0
    return anyGenerator({
    if count++ < self .numberOfDays {
    return self .randomDistribution.nextInt()
    } else {
    return nil
    }
    })
    }
    }

    View full-size slide

  64. import GameplayKit
    struct AppSales: SequenceType {
    let numberOfDays: Int
    let randomDistribution = GKGaussianDistribution(lowestValue: 0, highestValue: 10)
    func generate() -> Any Generator {
    var count = 0
    return anyGenerator({
    if count++ < self .numberOfDays {
    return self .randomDistribution.nextInt()
    } else {
    return nil
    }
    })
    }
    }

    View full-size slide

  65. let lastWeeksSales
    = AppSales(numberOfDays: 7)
    for dailySales in lastWeeksSales {
    print(dailySales)
    }

    View full-size slide

  66. AppSales is a
    SequenceType

    View full-size slide

  67. let lastWeeksSales
    = AppSales(numberOfDays: 7)
    for dailySales in lastWeeksSales {
    print(dailySales)
    }

    View full-size slide

  68. 6
    5
    6
    4
    6
    4
    3
    let lastWeeksSales
    = AppSales(numberOfDays: 7)
    for dailySales in lastWeeksSales {
    print(dailySales)
    }

    View full-size slide

  69. AppSales is a
    SequenceType

    View full-size slide

  70. map, filter, reduce, flatmap, …

    View full-size slide

  71. let lastWeeksSales = AppSales(numberOfDays: 7)
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * 1.99 * 0.70
    }

    View full-size slide

  72. let lastWeeksSales = AppSales(numberOfDays: 7)
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * 1.99 * 0.70
    }

    View full-size slide

  73. let lastWeeksSales = AppSales(numberOfDays: 7)
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * 1.99 * 0.70
    }

    View full-size slide

  74. let lastWeeksSales = AppSales(numberOfDays: 7)
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * 1.99 * 0.70
    }

    View full-size slide

  75. [6.964999999999999, 8.357999999999999,
    5.572, 6.964999999999999, 5.572,
    4.178999999999999, 4.178999999999999]
    let lastWeeksSales = AppSales(numberOfDays: 7)
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * 1.99 * 0.70
    }

    View full-size slide

  76. let lastWeeksSales = AppSales(numberOfDays: 7)
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * 1.99 * 0.70
    }

    View full-size slide

  77. let lastWeeksSales = AppSales(numberOfDays: 7)
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * 1.99 * 0.70
    }

    View full-size slide

  78. let lastWeeksSales = AppSales(numberOfDays: 7)
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * 1.99 * 0.70
    }

    View full-size slide

  79. let lastWeeksSales = AppSales(numberOfDays: 7)
    let unitPrice = 1.99
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * unitPrice * 0.70
    }

    View full-size slide

  80. let lastWeeksSales = AppSales(numberOfDays: 7)
    let unitPrice = 1.99
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * unitPrice * 0.70
    }

    View full-size slide

  81. let lastWeeksSales = AppSales(numberOfDays: 7)
    let unitPrice = 1.99
    let sellersPercentage = 0.70
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * unitPrice * sellersPercentage
    }

    View full-size slide

  82. let lastWeeksSales = AppSales(numberOfDays: 7)
    let unitPrice = 1.99
    let sellersPercentage = 0.70
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    Double(dailySales) * unitPrice * sellersPercentage
    }

    View full-size slide

  83. let lastWeeksSales = AppSales(numberOfDays: 7)
    let unitPrice = 1.99
    let sellersPercentage = 0.70
    func revenuesForCopies Sold(numberOfCopies: Int) -> Double {
    return Double(number OfCopies) * unitPrice * sellersPercentage
    }
    let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    revenuesForCopiesSold(dailySales)
    }

    View full-size slide

  84. let lastWeeksRevenues = lastWeeksSales.map{dailySales in
    revenuesForCopiesSold(dailySales)
    }

    View full-size slide

  85. let lastWeeksRevenues = lastWeeksSales.map{revenuesForCopies Sold($0) }

    View full-size slide

  86. let lastWeeksRevenues = lastWeeksSales.map(revenuesForCopies Sold)

    View full-size slide

  87. let lastWeeksRevenues = lastWeeksSales.map(revenuesForCopies Sold)

    View full-size slide

  88. Adjust the distribution

    View full-size slide

  89. let randomDistribution = GKGaussianDistribution(lowestValue: -5, highestValue: 15)

    View full-size slide

  90. Negatives count as 0

    View full-size slide

  91. Could filter copies > 0

    View full-size slide

  92. let lastWeeksRevenues = lastWeeksSales.filter{$0 > 0}
    .map(revenuesForCopiesSold)

    View full-size slide

  93. Filter can change
    size of array

    View full-size slide

  94. Could map
    negatives -> 0

    View full-size slide

  95. let lastWeeksRevenues = lastWeeksSales.map{$0 > 0 ? $0 : 0}
    .map(revenuesForCopiesSold)

    View full-size slide

  96. "Doctor it hurts when I do that."

    View full-size slide

  97. "Don't do that."

    View full-size slide

  98. let lastWeeksRevenues = lastWeeksSales.map{$0 > 0 ? $0 : 0}
    .map(revenuesForCopiesSold)

    View full-size slide

  99. func negativeNumbersToZero (number: Int) -> Int {
    return max(0, number)
    }
    let lastWeeksRevenues = lastWeeksSales.map(negativeNumbersToZero)
    .map(revenuesForCopiesSold)

    View full-size slide

  100. let lastWeeksRevenues = lastWeeksSales.map(negativeNumbersToZero)
    .map(revenuesForCopiesSold)

    View full-size slide

  101. let lastWeeksRevenues = lastWeeksSales.map(negativeNumbersToZero)
    .map(revenuesForCopiesSold)

    View full-size slide

  102. We'll come back
    to the Lasagne.

    View full-size slide

  103. First, the béchamel.

    View full-size slide

  104. func revenues ForCopiesSold(numberOfCopies: Int) -> Double {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }

    View full-size slide

  105. func revenues ForCopiesSold(numberOfCopies: Int) -> Double {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }

    View full-size slide

  106. typealias USDollars = Double
    func revenues ForCopiesSold(numberOfCopies: Int) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }

    View full-size slide

  107. typealias USDollars = Double
    func revenues ForCopiesSold(numberOfCopies: Int) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }
    func toThe NearestPenny(dollarAmount: USDollars) -> USDollars {
    return round(dollarAmount * 100)/100
    }

    View full-size slide

  108. typealias USDollars = Double
    func revenues ForCopiesSold(numberOfCopies: Int) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }
    func toThe NearestPenny(dollarAmount: USDollars) -> USDollars {
    return round(dollarAmount * 100)/100
    }
    func revenues InDollarsForCopiesSold(numberOfCopies: Int) -> USDollars {
    return toTheNearestPenny(revenuesForCopiesSold (numberOfCopies))
    }

    View full-size slide

  109. typealias USDollars = Double
    func revenues ForCopiesSold(numberOfCopies: Int) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }
    func toThe NearestPenny(dollarAmount: USDollars) -> USDollars {
    return round(dollarAmount * 100)/100
    }
    func revenues InDollarsForCopiesSold(numberOfCopies: Int) -> USDollars {
    return toTheNearestPenny(revenuesForCopiesSold (numberOfCopies))
    }

    View full-size slide

  110. typealias USDollars = Double
    func revenues ForCopiesSold(numberOfCopies: Int) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }
    func toThe NearestPenny(dollarAmount: USDollars) -> USDollars {
    return round(dollarAmount * 100)/100
    }
    func revenues InDollarsForCopiesSold(numberOfCopies: Int) -> USDollars {
    return toTheNearestPenny(revenuesForCopiesSold (numberOfCopies))
    }

    View full-size slide

  111. typealias USDollars = Double
    func revenues ForCopiesSold(numberOfCopies: Int) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }
    func toThe NearestPenny(dollarAmount: USDollars) -> USDollars {
    return round(dollarAmount * 100)/100
    }
    func revenues InDollarsForCopiesSold(numberOfCopies: Int) -> USDollars {
    return toTheNearestPenny(revenuesForCopiesSold (numberOfCopies))
    }

    View full-size slide

  112. func revenues InDollarsForCopiesSold(numberOfCopies: Int) -> USDollars {
    return toTheNearestPenny(revenuesForCopiesSold (numberOfCopies))
    }

    View full-size slide

  113. Method chaining

    View full-size slide

  114. Extensions
    UmmM, Daniel

    View full-size slide

  115. Extensions
    How did your
    talk get
    accepted?

    View full-size slide

  116. Extensions
    No Generics.

    View full-size slide

  117. Extensions
    No Custom
    Operators

    View full-size slide

  118. Custom Operator

    View full-size slide

  119. Custom Operator
    What?

    View full-size slide

  120. Custom Operator

    View full-size slide

  121. Custom Operator
    And Generics?

    View full-size slide

  122. infix operator » {associativity left}
    func »(input: T,
    transform: T -> U) -> U {
    return transform(input)
    }

    View full-size slide

  123. infix operator » {associativity left}
    func »(input: T,
    transform: T -> U) -> U {
    return transform(input)
    }

    View full-size slide

  124. infix operator » {associativity left}
    func »(input: T,
    transform: T -> U) -> U {
    return transform(input)
    }

    View full-size slide

  125. infix operator » {associativity left}
    func »(input: T,
    transform: T -> U) -> U {
    return transform(input)
    }

    View full-size slide

  126. infix operator » {associativity left}
    func »(input: T,
    transform: T -> U) -> U {
    return transform(input)
    }

    View full-size slide

  127. infix operator » {associativity left}
    func »(input: T,
    transform: T -> U) -> U {
    return transform(input)
    }

    View full-size slide

  128. infix operator » {associativity left}
    func »(input: T,
    transform: T -> U) -> U {
    return transform(input)
    }

    View full-size slide

  129. infix operator » {associativity left}
    func »(input: T,
    transform: T -> U) -> U {
    return transform(input)
    }

    View full-size slide

  130. func revenuesInDollarsForCopiesSold(number OfCopies: Int) -> USDollars {
    return numberOfCopies
    » revenuesForCopiesSold
    » toTheNearestPenny
    }

    View full-size slide

  131. func revenuesInDollarsForCopiesSold(number OfCopies: Int) -> USDollars {
    return numberOfCopies
    » revenuesForCopiesSold
    » toTheNearestPenny
    }

    View full-size slide

  132. func revenuesInDollarsForCopiesSold(number OfCopies: Int) -> USDollars {
    return numberOfCopies
    » revenuesForCopiesSold
    » toTheNearestPenny
    }

    View full-size slide

  133. func revenuesInDollarsForCopiesSold(number OfCopies: Int) -> USDollars {
    return numberOfCopies
    » revenuesForCopiesSold
    » toTheNearestPenny
    }

    View full-size slide

  134. func revenuesInDollarsForCopiesSold(number OfCopies: Int) -> USDollars {
    return numberOfCopies
    » revenuesForCopiesSold
    » toTheNearestPenny
    }

    View full-size slide

  135. func revenuesInDollarsForCopiesSold(number OfCopies: Int) -> USDollars {
    return numberOfCopies
    » revenuesForCopiesSold
    » toTheNearestPenny
    }

    View full-size slide

  136. Back to the Lasagne

    View full-size slide

  137. let lastWeeksRevenues = lastWeeksSales .map(negativeNumbersToZero)
    .map(revenuesInDollarsForCopiesSold)

    View full-size slide

  138. map is like -

    View full-size slide

  139. let lastWeeksRevenues = lastWeeksSales .map(negativeNumbersToZero)
    .map(revenuesInDollarsForCopiesSold)

    View full-size slide

  140. func replaceNegativeSalesWithZeroSales(sales: [Int]) -> [Int] {
    return sales.map(negativeNumbersToZero)
    }
    func calculateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.map(revenuesInDollarsFor CopiesSold)
    }

    View full-size slide

  141. func replaceNegativeSalesWithZeroSales(sales: [Int]) -> [Int] {
    return sales.map(negativeNumbersToZero)
    }
    func calculateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.map(revenuesInDollarsFor CopiesSold)
    }

    View full-size slide

  142. Types Don't Match

    View full-size slide

  143. let lastWeeksSales = AppSales(numberOfDays: 7)
    func replaceNegativeSalesWithZeroSales(sales: [Int]) -> [Int] {
    return sales.map(negativeNumbersToZero)
    }
    func calculateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.map(revenuesInDollarsFor CopiesSold)
    }

    View full-size slide

  144. func anArrayOfDailySales(rawSales: AppSales) -> [Int] {
    return rawSales.map{$0}
    }

    View full-size slide

  145. Chain them together

    View full-size slide

  146. let lastWeeksRevenues = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales

    View full-size slide

  147. let lastWeeksRevenues = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales

    View full-size slide

  148. let lastWeeksRevenues = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales

    View full-size slide

  149. let lastWeeksRevenues = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales

    View full-size slide

  150. let lastWeeksRevenues = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales

    View full-size slide

  151. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan

    View full-size slide

  152. let lastWeeksRevenues = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales

    View full-size slide

  153. We don't do this

    View full-size slide

  154. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    ̣ Butter
    ̣ Flour
    ̣ Milk
    ̣ Salt and Pepper
    » Grated parmesan

    View full-size slide

  155. let lastWeeksRevenues
    = lastWeeksSales
    .map{$0 > 0 ? $0 : 0}
    .map{round(Double($0) * unitPrice * sellersPercentage * 100)/100 }

    View full-size slide

  156. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan

    View full-size slide

  157. Lasagne
    » Bolognese sauce
    » Lasagne sheets
    » Béchamel sauce
    » Grated parmesan
    Bechamel Sauce
    » Butter
    » Flour
    » Milk
    » Salt and Pepper

    View full-size slide

  158. let lastWeeksRevenues = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales

    View full-size slide

  159. let lastWeeksRevenues = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales

    View full-size slide

  160. = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales
    func calculateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.map(revenuesInDollars ForCopiesSold)
    }

    View full-size slide

  161. = lastWeeksSales
    » anArrayOfDailySales
    » replaceNegativeSalesWithZeroSales
    » calculateRevenuesFromSales
    func calculateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.map(revenuesInDollarsForCopiesSold)
    }

    View full-size slide

  162. evenuesFromSales(sales: [Int]) -> [USDollars] {
    s.map(revenuesInDollarsForCopiesSold)
    func revenuesInDollarsForCopiesSold(numberOfCopies: Int) -> USDollars {
    return numberOfCopies
    » revenuesForCopiesSold
    » roundedToTheNearestPenny
    }

    View full-size slide

  163. evenuesFromSales(sales: [Int]) -> [USDollars] {
    s.map(revenuesInDollarsForCopiesSold)
    func revenuesInDollarsForCopiesSold(numberOfCopies: Int) -> USDollars {
    return numberOfCopies
    » revenuesForCopiesSold
    » roundedToTheNearestPenny
    }

    View full-size slide

  164. uesInDollarsForCopiesSold(numberOfCopies: Int) -> USDollars {
    numberOfCopies
    » revenuesForCopiesSold
    » roundedToTheNearestPenny
    func revenuesForCopiesSold(numberOfCopies: NumberOfCopies) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }

    View full-size slide

  165. func revenuesForCopiesSold(numberOfCopies: NumberOfCopies) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }

    View full-size slide

  166. func revenues ForCopiesSold(numberOfCopies: Int) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }

    View full-size slide

  167. func revenues ForCopiesSold(numberOfCopies: Int) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }

    View full-size slide

  168. typealias NumberOfCopies = Int
    func revenues ForCopiesSold(numberOfCopies: Number OfCopies) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
    }

    View full-size slide

  169. extension NumberOfCopies {
    private func revenuesForCopiesSold() -> USDollars {
    return Double(self) * unitPrice * sellersPercentage
    }
    }

    View full-size slide

  170. extension NumberOfCopies {
    private func revenuesForCopiesSold() -> USDollars {
    return Double(self) * unitPrice * sellersPercentage
    }
    }

    View full-size slide

  171. extension NumberOfCopies {
    private func revenuesForCopiesSold() -> USDollars {
    return Double(self) * unitPrice * sellersPercentage
    }
    }

    View full-size slide

  172. extension NumberOfCopies {
    private func revenuesForCopiesSold() -> USDollars {
    return Double(self) * unitPrice * sellersPercentage
    }
    }

    View full-size slide

  173. extension USDollars {
    private func roundedToTheNearestPenny() -> USDollars {
    return round(self * 100)/100
    }
    }

    View full-size slide

  174. extension USDollars {
    private func roundedToTheNearestPenny() -> USDollars {
    return round(self * 100)/100
    }
    }

    View full-size slide

  175. extension USDollars {
    private func roundedToTheNearestPenny() -> USDollars {
    return round(self * 100)/100
    }
    }

    View full-size slide

  176. func revenuesInDollarsForCopiesSold(number OfCopies: Int) -> USDollars {
    return numberOfCopies
    » revenuesForCopiesSold
    » roundedToTheNearestPenny
    }

    View full-size slide

  177. extension NumberOfCopies {
    private func revenuesIn DollarsForCopiesSold() -> USDollars {
    return self.revenues ForCopiesSold().roundedToTheNearestPenny ()
    }
    }

    View full-size slide

  178. extension NumberOfCopies {
    private func revenuesIn DollarsForCopiesSold() -> USDollars {
    return self.revenues ForCopiesSold().roundedToTheNearestPenny ()
    }
    }

    View full-size slide

  179. extension NumberOfCopies {
    private func revenuesIn DollarsForCopiesSold() -> USDollars {
    return self.revenues ForCopiesSold().roundedToTheNearestPenny ()
    }
    }

    View full-size slide

  180. extension NumberOfCopies {
    private func revenuesIn DollarsForCopiesSold() -> USDollars {
    return self.revenues ForCopiesSold().roundedToTheNearestPenny ()
    }
    }

    View full-size slide

  181. extension NumberOfCopies {
    private func revenuesIn DollarsForCopiesSold() -> USDollars {
    return self.revenues ForCopiesSold().roundedToTheNearestPenny ()
    }
    }

    View full-size slide

  182. extension NumberOfCopies {
    private func revenuesIn DollarsForCopiesSold() -> USDollars {
    return self.revenues ForCopiesSold().roundedToTheNearestPenny ()
    }
    }

    View full-size slide

  183. extension NumberOfCopies {
    private func revenuesIn DollarsForCopiesSold() -> USDollars {
    return self.revenues ForCopiesSold().roundedToTheNearestPenny ()
    }
    }

    View full-size slide

  184. 7.revenuesInDollarsForCopiesSold()

    View full-size slide

  185. 7.revenuesInDollarsForCopiesSold()
    9.75

    View full-size slide

  186. extension NumberOfCopies {
    private func revenues InDollarsForCopiesSold() -> USDollars {
    return revenues ForCopiesSold().roundedToTheNearestPenny ()
    }
    }

    View full-size slide

  187. That's Béchamel

    View full-size slide

  188. What about Lasagne?

    View full-size slide

  189. func replace NegativeSalesWithZeroSales(sales: [Int]) -> [Int] {
    return sales.map(negativeNumbersToZero)
    }

    View full-size slide

  190. extension [NumberOfCopies] {
    }

    View full-size slide

  191. extension [Int] {
    }

    View full-size slide

  192. Rich Hickey's Trolley

    View full-size slide

  193. Not bad for map()

    View full-size slide

  194. Wait a minute

    View full-size slide

  195. What does this have to
    do with Lasagne?

    View full-size slide

  196. Everything at once

    View full-size slide

  197. Fancy made to order

    View full-size slide

  198. Back to map()

    View full-size slide

  199. func anArrayOf DailySales(rawSales: AppSales) -> [Int] {
    return rawSales.map{$0}
    }
    func replace NegativeSalesWithZeroSales(sales: [Int]) -> [Int] {
    return sales.map(negativeNumbersToZero)
    }
    func calcu lateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.map(revenuesInDollarsForCopiesSold)
    }

    View full-size slide

  200. func processEndToEnd(sales: AppSales) -> USDollars {
    return sales.map(transform: Int -> U)
    }

    View full-size slide

  201. func anArrayOf DailySales(rawSales: AppSales) -> [Int] {
    return rawSales.map{$0}
    }
    func replace NegativeSalesWithZeroSales(sales: [Int]) -> [Int] {
    return sales.map(negativeNumbersToZero)
    }
    func calcu lateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.map(revenuesInDollarsForCopiesSold)
    }
    func processEndToEnd(sales: AppSales) -> USDollars {
    return sales.map(transform: Int -> U)
    }

    View full-size slide

  202. func processEndToEnd(sales: AppSales) -> USDollars {
    return sales.map(transform: Int -> U)
    }

    View full-size slide

  203. This doesn't work

    View full-size slide

  204. func process EndToEnd(sales: AppSales) -> USDollars {
    return sales
    .map(negativeNumbersToZero
    » revenuesInDollarsForCopiesSold)
    }

    View full-size slide

  205. Types don't match

    View full-size slide

  206. This works …

    View full-size slide

  207. func combinedSteps(input: Int) -> USDollars {
    return input » negativeNumbersToZero » revenuesInDollarsForCopiesSold
    }
    func processEndToEnd(sales: AppSales) -> [USDollars] {
    return sales.map(combinedSteps)
    }

    View full-size slide

  208. func combinedSteps(input: Int) -> USDollars {
    return input » negativeNumbersToZero » revenuesInDollarsForCopiesSold
    }
    func processEndToEnd(sales: AppSales) -> [USDollars] {
    return sales.map(combinedSteps)
    }

    View full-size slide

  209. func combinedSteps(input: Int) -> USDollars {
    return input » negativeNumbersToZero » revenuesInDollarsForCopiesSold
    }
    func processEndToEnd(sales: AppSales) -> [USDollars] {
    return sales.map(combinedSteps)
    }

    View full-size slide

  210. func combinedSteps(input: Int) -> USDollars {
    return input » negativeNumbersToZero » revenuesInDollarsForCopiesSold
    }
    func processEndToEnd(sales: AppSales) -> [USDollars] {
    return sales.map(combinedSteps)
    }

    View full-size slide

  211. func processEndToEnd(sales: AppSales) -> [USDollars] {
    return sales.map(negativeNumbersToZero » revenuesInDollarsForCopiesSold)
    }

    View full-size slide

  212. func » (firstFunction: T -> U, secondFunction: U -> V) -> T -> V {
    return {x in secondFunction(firstFunction(x)) }
    }

    View full-size slide

  213. func » (firstFunction: T -> U, secondFunction: U -> V) -> T -> V {
    return {x in secondFunction(firstFunction(x)) }
    }

    View full-size slide

  214. func » (firstFunction: T -> U, secondFunction: U -> V) -> T -> V {
    return {x in secondFunction(firstFunction(x)) }
    }

    View full-size slide

  215. func » (firstFunction: T -> U, secondFunction: U -> V) -> T -> V {
    return {x in secondFunction(firstFunction(x)) }
    }

    View full-size slide

  216. func » (firstFunction: T -> U, secondFunction: U -> V) -> T -> V {
    return {x in secondFunction(firstFunction(x)) }
    }

    View full-size slide

  217. let lastWeeksLazyRevenues = lastWeeksSales
    .map( negativeNumbersToZero
    » revenuesInDollarsForCopiesSold)

    View full-size slide

  218. let lastWeeksLazyRevenues = lastWeeksSales
    .map( negativeNumbersToZero
    » revenuesInDollarsForCopiesSold)

    View full-size slide

  219. let lastWeeksLazyRevenues = lastWeeksSales
    .map( negativeNumbersToZero
    » revenuesInDollarsForCopiesSold)

    View full-size slide

  220. let lastWeeksLazyRevenues = lastWeeksSales
    .map( negativeNumbersToZero
    » revenuesInDollarsForCopiesSold)

    View full-size slide

  221. Rich Hickey's Trolley

    View full-size slide

  222. flatmap
    T -> [U] [T] -> [ U]

    View full-size slide

  223. filter
    T -> Bool [T] -> [ T]

    View full-size slide

  224. map
    T -> U [T] -> [ U]

    View full-size slide

  225. reduce
    U, (U, T) -> U [T] -> U

    View full-size slide

  226. Mother Sauce

    View full-size slide

  227. Mother Sauce

    View full-size slide

  228. map with reduce

    View full-size slide

  229. filter with reduce

    View full-size slide

  230. flatmap with reduce

    View full-size slide

  231. Inefficient

    View full-size slide

  232. reduce
    U, (U, T) -> U

    View full-size slide

  233. reduce
    U, (U, T) -> U
    initial value

    View full-size slide

  234. reduce
    U, (U, T) -> U step

    View full-size slide

  235. reduce
    U, (U, T) -> U

    View full-size slide

  236. map with reduce

    View full-size slide

  237. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  238. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  239. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  240. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  241. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  242. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  243. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  244. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  245. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  246. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  247. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  248. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  249. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  250. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  251. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  252. extension SequenceType {
    func mapUsingReduce (transform: Generator.Element -> U) -> [U] {
    let initialValue = [U]()
    func step(accu mulatedValue: [U], nextElement: Generator .Element) -> [U] {
    return acc umulatedValue + [transform(nextElement)]
    }
    return reduce (initialValue, combine: step)
    }
    }

    View full-size slide

  253. map with reduce

    View full-size slide

  254. filter with reduce

    View full-size slide

  255. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  256. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  257. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  258. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  259. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  260. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  261. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  262. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  263. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  264. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  265. func filterUsingReduce (includeElement: Generator.Element -> Bool) -> [Generator.Element] {
    let initialValue = Array()
    func step(accumula tedValue: [Generator.Element],
    next Element: Generator.Element) -> [Generator .Element] {
    guard include Element(nextElement) else {
    return acc umulatedValue
    }
    return accumula tedValue + [nextElement]
    }
    return reduce(ini tialValue, combine: step)
    }

    View full-size slide

  266. filter with reduce

    View full-size slide

  267. func anArrayOfDailySales(rawSales: AppSales) -> [Int] {
    return rawSales.map{$0}
    }
    func replaceNegativeSalesWithZero Sales(sales: [Int]) -> [Int] {
    return sales.map(negative NumbersToZero)
    }
    func calculateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.map(revenuesInDollars ForCopiesSold)
    }

    View full-size slide

  268. func anArrayOfDailySales(rawSales: AppSales) -> [Int] {
    return rawSales.mapUsingReduce{$0}
    }
    func replaceNegativeSalesWithZero Sales(sales: [Int]) -> [Int] {
    return sales.mapUsingReduce(negative NumbersToZero)
    }
    func calculateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.mapUsingReduce(revenues InDollarsForCopiesSold)
    }

    View full-size slide

  269. Still need lots of trolleys

    View full-size slide

  270. Performance is worse

    View full-size slide

  271. Compiler Optimizations

    View full-size slide

  272. One reduce()

    View full-size slide

  273. Swift solution?

    View full-size slide

  274. transducers?

    View full-size slide

  275. Nothing official yet

    View full-size slide

  276. Search:
    transducers in Swift

    View full-size slide

  277. Idea - chain steps in reduce

    View full-size slide

  278. reduce
    U, (U, T) -> U

    View full-size slide

  279. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  280. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  281. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  282. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  283. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  284. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  285. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  286. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  287. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  288. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  289. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  290. This seems confusing

    View full-size slide

  291. Are you sure you
    understand this?

    View full-size slide

  292. Not Even
    Speaker
    Colleagues
    Everyone
    Parents

    View full-size slide

  293. Not Even
    Speaker
    Parents

    View full-size slide

  294. transducer
    U, (U, T) -> U U, (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  295. Start from the last step

    View full-size slide

  296. Use reduce
    [USDollars], ([USDollars], NumberOfCopies) -> [USDollars]
    revenuesInDollarsForCopiesSold: NumberOfCopies -> USDollars
    [NumberOfCopies] -> [USDollars]

    View full-size slide

  297. Use reduce
    [USDollars], ([USDollars], NumberOfCopies) -> [USDollars]
    revenuesInDollarsForCopiesSold: NumberOfCopies -> USDollars
    [NumberOfCopies] -> [USDollars]

    View full-size slide

  298. Use reduce
    [USDollars], ([USDollars], NumberOfCopies) -> [USDollars]
    revenuesInDollarsForCopiesSold: NumberOfCopies -> USDollars
    [NumberOfCopies] -> [USDollars]

    View full-size slide

  299. Use reduce
    [USDollars], ([USDollars], NumberOfCopies) -> [USDollars]
    revenuesInDollarsForCopiesSold: NumberOfCopies -> USDollars
    [NumberOfCopies] -> [USDollars]

    View full-size slide

  300. Use reduce
    [USDollars], ([USDollars], NumberOfCopies) -> [USDollars]
    revenuesInDollarsForCopiesSold: NumberOfCopies -> USDollars
    [NumberOfCopies] -> [USDollars]

    View full-size slide

  301. Use reduce
    [USDollars], ([USDollars], NumberOfCopies) -> [USDollars]
    revenuesInDollarsForCopiesSold: NumberOfCopies -> USDollars
    [NumberOfCopies] -> [USDollars]

    View full-size slide

  302. Chain in another operation

    View full-size slide

  303. transducer
    U,
    (U, T) -> U
    U,
    (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  304. transducer
    U,
    (U, T) -> U
    U,
    (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  305. transducer
    U,
    (U, T) -> U
    U,
    (U, S) -> U
    f: S -> T
    [T] -> U [S] -> U

    View full-size slide

  306. transducer
    [USDollars],
    ([USDollars], T) -> [USDollars]
    [USDollars],
    ([USDollars], S) -> [USDollars]
    f: S -> T
    [T] -> [USDollars] [S] -> [USDollars]

    View full-size slide

  307. transducer
    [USDollars],
    ([USDollars], T) -> [USDollars]
    [USDollars],
    ([USDollars], S) -> [USDollars]
    f: S -> T
    [T] -> [USDollars] [S] -> [USDollars]

    View full-size slide

  308. transducer
    [USDollars],
    ([USDollars], NumberOfCopies)
    -> USDollars
    [USDollars],
    ([USDollars], S) -> [USDollars]
    f: S -> NumberOfCopies
    [NumberOfCopies] -> [USDollars] [S] -> [USDollars]

    View full-size slide

  309. transducer
    [USDollars],
    ([USDollars], NumberOfCopies)
    -> USDollars
    [USDollars],
    ([USDollars], S) -> [USDollars]
    f: S -> NumberOfCopies
    [NumberOfCopies] -> [USDollars] [S] -> [USDollars]
    reduce with revenueInDollarsForCopiesSold

    View full-size slide

  310. transducer
    [USDollars],
    ([USDollars], NumberOfCopies)
    -> USDollars
    [USDollars],
    ([USDollars], S) -> [USDollars]
    f: S -> NumberOfCopies
    [NumberOfCopies] -> [USDollars] [S] -> [USDollars]

    View full-size slide

  311. transducer
    [USDollars],
    ([USDollars], NumberOfCopies)
    -> USDollars
    [USDollars],
    ([USDollars], S) -> [USDollars]
    negativeNumbersToZero:
    NumberOfCopies -> NumberOfCopies
    [NumberOfCopies] -> [USDollars] [S] -> [USDollars]

    View full-size slide

  312. transducer
    [USDollars],
    ([USDollars], NumberOfCopies)
    -> USDollars
    [USDollars],
    ([USDollars], S) -> [USDollars]
    negativeNumbersToZero:
    Int -> NumberOfCopies
    [NumberOfCopies] -> [USDollars] [S] -> [USDollars]

    View full-size slide

  313. transducer
    [USDollars],
    ([USDollars], NumberOfCopies)
    -> USDollars
    [USDollars],
    ([USDollars], Int) -> [USDollars]
    negativeNumbersToZero:
    Int -> NumberOfCopies
    [NumberOfCopies] -> [USDollars] [Int] -> [USDollars]

    View full-size slide

  314. transducer
    [USDollars],
    ([USDollars], NumberOfCopies)
    -> USDollars
    [USDollars],
    ([USDollars], Int) -> [USDollars]
    negativeNumbersToZero:
    Int -> NumberOfCopies
    [NumberOfCopies] -> [USDollars] [Int] -> [USDollars]
    reduce implementation of the composition

    View full-size slide

  315. One reduce()

    View full-size slide

  316. Swift Solution?

    View full-size slide

  317. Keep your code…

    View full-size slide

  318. Well factored

    View full-size slide