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. View Slide

  2. View Slide

  3. View Slide

  4. Handwritten Slides?

    View Slide

  5. Boring Handwritten
    Slides

    View Slide

  6. This Talk Sucks

    View Slide

  7. I'm Already
    nodding off

    View Slide

  8. Not Even
    Speaker
    Colleagues
    Everyone
    Parents

    View Slide

  9. Let's start

    View Slide

  10. Recipe

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  14. Recipe

    View Slide

  15. Lasagne

    View Slide

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

    View Slide

  17. Context

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  25. Context matters

    View Slide

  26. Context matters

    View Slide

  27. An Obj-C example

    View Slide

  28. An Obj-C example

    View Slide

  29. An Obj-C example

    View Slide

  30. The model

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  38. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  48. Context

    View Slide

  49. Clean

    View Slide

  50. Clear

    View Slide

  51. Lasagne

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  58. The model in Swift

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  66. Clean

    View Slide

  67. Compact

    View Slide

  68. Clear

    View Slide

  69. UmmM, Daniel

    View Slide

  70. You Started
    with Obj-C

    View Slide

  71. And converted
    it to Swift

    View Slide

  72. What about
    Real Swift

    View Slide

  73. Show me Map,
    Filter, reduce!

    View Slide

  74. Silly Example

    View Slide

  75. App Sales

    View Slide

  76. 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 Slide

  77. 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 Slide

  78. 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 Slide

  79. 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 Slide

  80. 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 Slide

  81. 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 Slide

  82. 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 Slide

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

    View Slide

  84. AppSales is a
    SequenceType

    View Slide

  85. for in

    View Slide

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

    View Slide

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

    View Slide

  88. AppSales is a
    SequenceType

    View Slide

  89. map, filter, reduce, flatmap, …

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  94. [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 Slide

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

    View Slide

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

    View Slide

  97. Context

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  103. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  108. Adjust the distribution

    View Slide

  109. Wider

    View Slide

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

    View Slide

  111. Negatives count as 0

    View Slide

  112. Could filter copies > 0

    View Slide

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

    View Slide

  114. Filter can change
    size of array

    View Slide

  115. Could map
    negatives -> 0

    View Slide

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

    View Slide

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

    View Slide

  118. "Don't do that."

    View Slide

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

    View Slide

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

    View Slide

  121. Good News

    View Slide

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

    View Slide

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

    View Slide

  124. We'll come back
    to the Lasagne.

    View Slide

  125. First, the béchamel.

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  129. 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 Slide

  130. 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 Slide

  131. 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 Slide

  132. 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 Slide

  133. 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 Slide

  134. Backwards

    View Slide

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

    View Slide

  136. Method chaining

    View Slide

  137. Extensions

    View Slide

  138. Extensions
    UmmM, Daniel

    View Slide

  139. Extensions
    How did your
    talk get
    accepted?

    View Slide

  140. Extensions
    No Generics.

    View Slide

  141. Extensions
    No Custom
    Operators

    View Slide

  142. Custom Operator

    View Slide

  143. Custom Operator
    What?

    View Slide

  144. Custom Operator

    View Slide

  145. Custom Operator
    And Generics?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  153. Clearly …

    View Slide

  154. Context

    View Slide

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

    View Slide

  156. Use it

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  163. Back to the Lasagne

    View Slide

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

    View Slide

  165. map is like -

    View Slide

  166. Move map

    View Slide

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

    View Slide

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

    View Slide

  169. Types Match

    View Slide

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

    View Slide

  171. Types Don't Match

    View Slide

  172. 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 Slide

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

    View Slide

  174. Chain them together

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  180. Lasagne

    View Slide

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

    View Slide

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

    View Slide

  183. We don't do this

    View Slide

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

    View Slide

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

    View Slide

  186. We zoom in

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  197. View Slide

  198. Clean

    View Slide

  199. Clear

    View Slide

  200. Testable

    View Slide

  201. Context

    View Slide

  202. And yet …

    View Slide

  203. »

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  222. 7.revenuesInDollarsForCopiesSold()

    View Slide

  223. 7.revenuesInDollarsForCopiesSold()
    9.75

    View Slide

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

    View Slide

  225. Removed »

    View Slide

  226. That's Béchamel

    View Slide

  227. What about Lasagne?

    View Slide

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

    View Slide

  229. Where?

    View Slide

  230. extension [NumberOfCopies] {
    }

    View Slide

  231. Can't

    View Slide

  232. extension [Int] {
    }

    View Slide

  233. Still Can't

    View Slide

  234. Rich Hickey's Trolley

    View Slide

  235. Not bad for map()

    View Slide

  236. Wait a minute

    View Slide

  237. What does this have to
    do with Lasagne?

    View Slide

  238. Everything at once

    View Slide

  239. Fancy made to order

    View Slide

  240. Back to map()

    View Slide

  241. Combine

    View Slide

  242. 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 Slide

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

    View Slide

  244. Combine

    View Slide

  245. 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 Slide

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

    View Slide

  247. This doesn't work

    View Slide

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

    View Slide

  249. Types don't match

    View Slide

  250. This works …

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  255. Want…

    View Slide

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

    View Slide

  257. The types

    View Slide

  258. Overload »

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  268. map

    View Slide

  269. Rich Hickey's Trolley

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  274. View Slide

  275. reduce

    View Slide

  276. Béchamel

    View Slide

  277. Mother Sauce

    View Slide

  278. reduce

    View Slide

  279. Mother Sauce

    View Slide

  280. map with reduce

    View Slide

  281. filter with reduce

    View Slide

  282. flatmap with reduce

    View Slide

  283. Inefficient

    View Slide

  284. Instructive

    View Slide

  285. reduce

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  290. map with reduce

    View Slide

  291. 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 Slide

  292. 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 Slide

  293. 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 Slide

  294. 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 Slide

  295. 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 Slide

  296. 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 Slide

  297. 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 Slide

  298. 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 Slide

  299. 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 Slide

  300. 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 Slide

  301. 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 Slide

  302. 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 Slide

  303. 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 Slide

  304. 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 Slide

  305. 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 Slide

  306. 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 Slide

  307. map with reduce

    View Slide

  308. filter with reduce

    View Slide

  309. 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 Slide

  310. 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 Slide

  311. 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 Slide

  312. 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 Slide

  313. 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 Slide

  314. 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 Slide

  315. 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 Slide

  316. 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 Slide

  317. 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 Slide

  318. 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 Slide

  319. 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 Slide

  320. filter with reduce

    View Slide

  321. Use these?

    View Slide

  322. 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 Slide

  323. Easy!

    View Slide

  324. 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 Slide

  325. Still need lots of trolleys

    View Slide

  326. View Slide

  327. Performance is worse

    View Slide

  328. Compiler Optimizations

    View Slide

  329. Transducers

    View Slide

  330. View Slide

  331. One reduce()

    View Slide

  332. Chain steps

    View Slide

  333. Swift solution?

    View Slide

  334. lazy?

    View Slide

  335. transducers?

    View Slide

  336. Nothing yet

    View Slide

  337. Nothing official yet

    View Slide

  338. Search:
    transducers in Swift

    View Slide

  339. Idea - chain steps in reduce

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  352. This seems confusing

    View Slide

  353. Are you sure you
    understand this?

    View Slide

  354. Not Even
    Speaker
    Colleagues
    Everyone
    Parents

    View Slide

  355. Not Even
    Speaker
    Parents

    View Slide

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

    View Slide

  357. Start from the last step

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  364. Chain in another operation

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  377. transducer

    View Slide

  378. One reduce()

    View Slide

  379. Chain steps

    View Slide

  380. Swift Solution?

    View Slide

  381. Not yet

    View Slide

  382. Keep your code…

    View Slide

  383. Clear

    View Slide

  384. Clean

    View Slide

  385. Concise

    View Slide

  386. Well factored

    View Slide

  387. Testable

    View Slide

  388. Swift

    View Slide

  389. View Slide