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

Less Imperative with More Kotlin

Less Imperative with More Kotlin

Huyen's talk given at a Night Discussing Kotlin @ Foursquare HQ discussing basic definitions and terms related to Functional Programming and relating them to Kotlin.

Huyen Tue Dao

December 13, 2017
Tweet

More Decks by Huyen Tue Dao

Other Decks in Programming

Transcript

  1. LESS IMPERATIVE
    WITH MORE
    HUYEN TUE DAO
    @QUEENCODEMONKEY

    View Slide

  2. Alright. Let’s talk terms.

    View Slide

  3. IMPERATIVE
    PROGRAMMING
    a sequence of statements that
    change state.

    View Slide

  4. focuses on actions.
    explicit control flow.
    IMPERATIVE
    PROGRAMMING

    View Slide

  5. paradigm by which you
    describe how to do something.
    IMPERATIVE
    PROGRAMMING

    View Slide

  6. 100 REM FIND THE SUM OF THE TWO NUMBERS
    200 LET X=9
    300 LET Y=6
    400 LET Z=X+Y
    500 PRINT X,Y,Z
    600 END

    View Slide

  7. fun average(numbers: List): Float {
    var total = 0f
    for (i in 0 until numbers.size) {
    total += numbers[i]
    }
    return total / numbers.size
    }

    View Slide

  8. DECLARATIVE
    PROGRAMMING
    describe what you want to do.

    View Slide

  9. CAVEAT
    you or someone you encounter on
    StackOverflow may find this too fluffy,
    simplistic, imprecise, ambiguous.
    that’s okay.
    let’s keep this chill and practical.

    View Slide

  10. DECLARATIVE
    PROGRAMMING
    describe what you want to do.

    View Slide

  11. DECLARATIVE
    STYLE
    describe what you want to do.

    View Slide



  12. Heyo, Foursquare!
    What's up?


    View Slide

  13. SELECT *
    FROM [Builds]
    WHERE [Efficacy] = 'OP'

    View Slide

  14. fun average(numbers: List): Float {A
    var total = 0
    forA(i in 0Auntil numbers.size) {
    total += numbers[i]
    }
    return total.toFloat() / numbers.size
    }A

    View Slide

  15. fun average(numbers: List): Float {A
    val total = numbers.sum()
    return total.toFloat() / numbers.size
    }A

    View Slide

  16. DECLARATIVE
    STYLE
    “…coding in the imperative style is like
    talking to a toddler.”
    Venkat Subramaniam

    View Slide

  17. DECLARATIVE
    STYLE
    “The declarative version is like
    speaking to a responsible adult.”
    Venkat Subramaniam

    View Slide

  18. Take your first left.
    Continue straight 2 miles.
    Slight right onto Raynor St.
    Left onto Kerrigan Ave.
    Continue straight .2 miles.
    DECLARATIVE
    IMPERATIVE
    My address is
    8 Kerrigan Ave
    Reference, CO 88888
    Tyler McGinnis
    “How do I get to your house from here?”

    View Slide

  19. fun average(numbers: List): Float {A
    var total = 0
    forA(i in 0Auntil numbers.size) {
    total += numbers[i]
    }
    return total.toFloat() / numbers.size
    }A

    View Slide

  20. fun average(numbers: List): Float {A
    val total = numbers.sum()
    return total.toFloat() / numbers.size
    }A

    View Slide

  21. FUNCTIONAL
    PROGRAMMING

    View Slide

  22. FUNCTIONAL
    STYLE

    View Slide

  23. FUNCTIONAL
    PROGRAMMING
    some disagreement on exact definition.

    View Slide

  24. FUNCTIONAL
    PROGRAMMING
    style of programming based on
    evaluating functions

    View Slide

  25. FUNCTIONAL
    PROGRAMMING
    style of programming based on
    evaluating f: x → f(x)

    View Slide

  26. FUNCTIONAL
    PROGRAMMING
    style of programming based on
    evaluating expressions

    View Slide

  27. STATEMENTS
    EXPRESSIONS
    computations.
    actions.

    View Slide

  28. fun average(numbers: List): Float {A
    var total = 0
    forA(i in 0Auntil numbers.size) {
    total += numbers[i]
    }
    return total.toFloat() / numbers.size
    }A

    View Slide

  29. fun average(numbers: List): Float {A
    val total = numbers.sum()
    return total.toFloat() / numbers.size
    }A

    View Slide

  30. fun average(numbers: List) =
    numbers.sum().toFloat() / numbers.size

    View Slide

  31. FUNCTIONAL
    PROGRAMMING
    mathematical, theoretical foundations.
    Category Theory. λ-calculus.
    many high-level and abstract concepts.

    View Slide

  32. Let’s start with
    basic and practical,
    exploring a different
    way of thinking

    View Slide

  33. var count = 1
    fun calculate(x: Int, y: Int): Int {A
    count++
    return x + y
    }A

    View Slide

  34. what are side effects?
    SIDE EFFECTS
    when a function makes
    modifications of outside state

    View Slide

  35. what are side effects?
    SIDE EFFECTS
    name sets them apart from
    main result of function.

    View Slide

  36. fun calculateAndCache(x: Int, y: Int): Int {
    val value = x + y
    val sharedPrefs = getPreferences(Context.MODE_PRIVATE)
    sharedPrefs
    .edit()
    .putInt("lastValue", value)
    .apply()
    return value
    }

    View Slide

  37. var count = 1
    fun calculate(x: Int, y: Int): Int {A
    return x + y - count
    }A

    View Slide

  38. fun calculate(x: Int, y: Int): Int {
    val value = x + y +
    resources.getInteger(R.integer.some_important_integer)
    return value
    }

    View Slide

  39. when a function utilizes
    outside state or I/O
    SIDE CAUSES Kris Jenkins

    View Slide

  40. when a function makes
    modifications of outside state
    SIDE EFFECTS

    View Slide

  41. when a function interacts
    with the outside world
    SIDE EFFECTS

    View Slide

  42. SIDE EFFECTS
    “Wait. Isn’t that just programming?”

    View Slide

  43. SIDE EFFECTS
    apps need to interact
    with the outside world

    View Slide

  44. Here comes the “but”…

    View Slide

  45. make code harder
    to trace and understand.
    SIDE EFFECTS

    View Slide

  46. make code harder to test and debug.
    have to re-create the environment.
    SIDE EFFECTS

    View Slide

  47. therefore, can be a source of bugs.
    SIDE EFFECTS

    View Slide

  48. but we need them.
    so we want to limit and control them.
    SIDE EFFECTS

    View Slide

  49. FUNCTIONAL
    PROGRAMMING
    style of programming based on
    evaluating expressions

    View Slide

  50. FUNCTIONAL
    PROGRAMMING
    “Functional code is characterised by
    one thing: the absence of side effects.”
    Mary Rose Cook

    View Slide

  51. FUNCTIONAL
    PROGRAMMING
    “Every other ‘functional’ thing can be
    derived from this property.”
    Mary Rose Cook

    View Slide

  52. FUNCTIONAL
    PROGRAMMING
    No side effects.
    Immutability.
    Higher-order functions.
    Kotlin in Action

    View Slide

  53. FUNCTIONAL
    PROGRAMMING
    No side effects.
    Immutability.
    Higher-order functions.
    Kotlin in Action

    View Slide

  54. result depends only on the inputs.
    there are no side effects.
    PURE FUNCTIONS

    View Slide

  55. idempotent
    function that has the property
    that: f(f(x)) → f(x)
    PURE FUNCTIONS

    View Slide

  56. idempotent
    multiple calls with same inputs
    has same effect as one call.
    PURE FUNCTIONS

    View Slide

  57. var count = 0
    fun increment() {
    count++ // count = 1
    count++ // count = 2
    count++ // count = 3
    count++ // count = 4
    }

    View Slide

  58. nullipotent
    calling function zero times
    has same effect as calling it once.
    PURE FUNCTIONS

    View Slide

  59. referential transparency
    an expression or function
    may be safely replaced by its value.
    PURE FUNCTIONS

    View Slide

  60. var count = 0
    fun calculate(x: Int, y: Int): Int {A
    return x + y
    }A
    val result = calculate(1, 2)
    // result = 3, count = 0

    View Slide

  61. var count = 0
    fun calculate(x: Int, y: Int): Int {
    return x + y
    }A
    val result = 3
    // result = 3, count = 0

    View Slide

  62. var count = 0
    fun calculate(x: Int, y: Int): Int {A
    count++
    return x + y
    }A
    val result = calculate(1, 2)
    // result = 3, count = 1

    View Slide

  63. var count = 0
    fun calculate(x: Int, y: Int): Int {A
    count++
    return x + y
    }A
    val result = 3
    // result = 3, count = 0

    View Slide

  64. referential transparency
    an expression or function
    may be safely replaced by its value.
    PURE FUNCTIONS

    View Slide

  65. Absence of side effects.
    PURE FUNCTIONS

    View Slide

  66. Encourages separation of concerns.
    PURE FUNCTIONS

    View Slide

  67. Easier to understand and test.
    PURE FUNCTIONS

    View Slide

  68. FUNCTIONAL
    PROGRAMMING
    No side effects.
    Immutability.
    Higher-order functions.
    Kotlin in Action

    View Slide

  69. FUNCTIONAL
    PROGRAMMING
    No side effects.
    Immutability.
    Higher-order functions.
    Kotlin in Action

    View Slide

  70. FUNCTIONAL
    PROGRAMMING
    No side effects.
    Immutability.
    Higher-order functions.
    Kotlin in Action

    View Slide

  71. So what are the
    benefits?

    View Slide

  72. Easier to understand.

    View Slide

  73. More concise.

    View Slide

  74. More maintainable.

    View Slide

  75. Easier testing.

    View Slide

  76. Safer multithreading.

    View Slide

  77. Less error-prone.

    View Slide

  78. FUNCTIONAL
    BITS OF

    View Slide

  79. FUNCTIONAL
    BITS OF
    function types + lambdas.

    View Slide

  80. FUNCTIONAL
    BITS OF
    data classes + immutable collections

    View Slide

  81. FUNCTIONAL
    BITS OF
    functional style APIs in the stdlib

    View Slide

  82. FUNCTIONAL
    BITS OF
    functional is not required.
    can live next to imperative and OOP code.

    View Slide

  83. Let’s start thinking
    functionally with .

    View Slide

  84. fun average(numbers: List): Float {A
    val total = numbers.sum()
    return total.toFloat() / numbers.size
    }A

    View Slide

  85. fun average(numbers: List) =
    numbers.sum().toFloat() / numbers.size

    View Slide

  86. fun average(numbers: List) =
    numbers.sum().toFloat() / numbers.size
    immutability

    View Slide

  87. fun average(numbers: List) =
    numbers.sum().toFloat() / numbers.size
    pure function

    View Slide

  88. fun average(numbers: List) =
    numbers.sum().toFloat() / numbers.size
    pure function
    depends only on input same inputs yield same output

    View Slide

  89. fun average(numbers: List) =
    numbers.sum().toFloat() / numbers.size

    View Slide

  90. fun average(numbers: List) =
    numbers.average()

    View Slide

  91. stdlib is full of
    functional operators.

    View Slide

  92. functional operators
    are awesome.

    View Slide

  93. let’s talk about mapping.

    View Slide

  94. val films = listOf(
    Movie("Beauty and the Beast", 2017, 504.1f),
    Movie("Guardians of the Galaxy Vol. 2", 2017, 389.8f),
    Movie("Dunkirk", 2017, 188.5f),
    Movie("Rogue One", 2016, 532.18f),
    Movie("Finding Dory", 2016, 486.30f),
    Movie("Deadpool", 2016, 363.07f),
    Movie("Fantastic Beasts and Where to Find Them", 2016, 234.04f),
    Movie("Hidden Figures", 2016, 169.39f),
    Movie("Star Wars: The Force Awakens", 2015, 936.66f),
    Movie("Jurassic World", 2015, 652.27f),
    Movie("Avengers: Age of Ultron", 2015, 459.01f),
    Movie("Inside Out", 2015, 356.46f)
    )

    View Slide

  95. fun getFilmTitles(films: List): List {A
    val names = mutableListOf()
    for (film in films) {
    names.add(film.name)
    }
    return names
    }A

    View Slide

  96. fun getFilmTitles(films: List): List {A
    return films.map { film -> film.name }
    }A

    View Slide

  97. fun getFilmTitles(films: List): List {A
    return films.map { film -> film.name }
    }A

    View Slide

  98. Iterable.map(transform: (T) -> R): List

    View Slide

  99. extension function
    Iterable.map(transform: (T) -> R): List

    View Slide

  100. Iterable.map(transform: (T) -> R): List
    immutability

    View Slide

  101. Iterable.map(transform: (T) -> R): List
    higher-order function

    View Slide

  102. fun getFilmTitles(films: List): List {A
    val names = mutableListOf()
    for (film in films) {
    names.add(film.name)
    }
    return names
    }A

    View Slide

  103. fun getFilmTitles(films: List): List {A
    return films.map { film -> film.name }
    }A
    let’s sprinkle on some sugar.

    View Slide

  104. fun getFilmTitles(films: List) =
    films.map { it.name }

    View Slide

  105. fun getFilmTitles(films: List) =
    films.map { it.name }
    expression body
    implicit single parameter name

    View Slide

  106. fun getFilmTitles(films: List) =
    films.map { it.name }

    View Slide

  107. fun getFilmTitles(films: List) =
    films.map(Movie::name)
    property reference

    View Slide

  108. let’s talk about folding.

    View Slide

  109. fun totalGross(films: List): Float {
    var gross:Float = 0f
    for (film in films) {
    gross += film.gross
    }
    return gross
    }

    View Slide

  110. fun totalGross(films: List): Float {
    return films.fold(0f) { gross, film ->
    gross + film.gross
    }
    }

    View Slide

  111. fun totalGross(films: List): Float {
    return films.fold(0f) { gross, film ->
    gross + film.gross
    }
    }

    View Slide

  112. fun Iterable.fold(initial: R, operation: (acc: R, T) -> R): R

    View Slide

  113. fun Iterable.fold(initial: R, operation: (acc: R, T) -> R): R
    fun Iterable.fold(initial: R, operation: (acc: R, T) -> R): R
    pure function

    View Slide

  114. fun Iterable.fold(initial: R, operation: (acc: R, T) -> R): R
    extension function

    View Slide

  115. fun Iterable.fold(initial: R, operation: (acc: R, T) -> R): R
    immutability

    View Slide

  116. fun Iterable.fold(initial: R, operation: (acc: R, T) -> R): R
    higher-order function

    View Slide

  117. fun totalGross(films: List): Float {
    return films.fold(0f) { gross, film ->
    gross + film.gross
    }
    }

    View Slide

  118. fun totalGross(films: List): Float {
    return films.fold(0f) { gross, film ->
    gross + film.gross
    }
    }

    View Slide

  119. fun totalGross(films: List): Float {
    return films.fold(0f) { gross, film ->
    gross + film.gross
    }
    }

    View Slide

  120. let’s sprinkle on some sugar.
    fun totalGross(films: List): Float {
    return films.fold(0f) { gross, film ->
    gross + film.gross
    }
    }

    View Slide

  121. fun totalGross(films: List) =
    films.sumByDouble { movie -> movie.gross.toDouble() }

    View Slide

  122. let’s talk about filtering.

    View Slide

  123. fun moviesFrom2017(films: List): List {
    val results = mutableListOf()
    for (film in films) {
    if (film.year == 2017) {
    results.add(film)
    }
    }
    return results
    }

    View Slide

  124. fun moviesFrom2017(films: List) =
    films.filter { it.year == 2017 }

    View Slide

  125. fun moviesFrom2017(films: List) =
    films.filter { it.year == 2017 }

    View Slide

  126. fun Iterable.filter(predicate: (T) -> Boolean): List

    View Slide

  127. fun Iterable.filter(predicate: (T) -> Boolean): List
    pure function

    View Slide

  128. fun Iterable.filter(predicate: (T) -> Boolean): List
    immutability

    View Slide

  129. fun Iterable.filter(predicate: (T) -> Boolean): List
    higher-order function

    View Slide

  130. fun moviesFrom2017(films: List) =
    films.filter { it.year == 2017 }

    View Slide

  131. println("2016 Films = ${films.filter { it.year == year }}")

    View Slide

  132. val greaterThan100M = { movie: Movie -> movie.gross > 100.0f }
    println("2016 Films = ${films.filter(greaterThan100M)}")
    starting to look like a strategy pattern

    View Slide

  133. val greaterThan100M = { movie: Movie -> movie.gross > 100.0f }
    println("2016 Films = ${films.filter(greaterThan100M)}")
    starting to look like a strategy pattern

    View Slide

  134. now for some composition.

    View Slide

  135. val names = films
    .filter { it.year == 2016 && it.gross > 100f }
    .map { it.name }
    println("Name of 2016 Films Grossing More Than $100M = $names")

    View Slide

  136. experiment with creating
    declarative structures.

    View Slide

  137. interface Map
    V computeIfAbsent(K key, Function super K,? extends V> mappingFunction)
    V computeIfPresent(K key, Function super K,? extends V> mappingFunction)
    let’s make our own and
    sprinkle on function types

    View Slide

  138. inline fun MutableMap.computeIf(key: K,
    predicate: (K, V?) -> Boolean,
    mappingFunction: (K, V?) -> V?): V? {
    val oldValue = get(key)
    if (!predicate(key, oldValue)) return oldValue
    val newValue = mappingFunction(key, oldValue)
    if (newValue == oldValue) return newValue
    if (newValue != null) put(key, newValue)
    else if (oldValue != null) remove(key)
    return newValue
    }

    View Slide

  139. inline fun MutableMap.computeIf(key: K,
    predicate: (K, V?) -> Boolean,
    mappingFunction: (K, V?) -> V?): V? {
    val oldValue = get(key)
    if (!predicate(key, oldValue)) return oldValue
    val newValue = mappingFunction(key, oldValue)
    if (newValue == oldValue) return newValue
    if (newValue != null) put(key, newValue)
    else if (oldValue != null) remove(key)
    return newValue
    }
    extension function

    View Slide

  140. inline fun MutableMap.computeIf(key: K,
    predicate: (K, V?) -> Boolean,
    mappingFunction: (K, V?) -> V?): V? {
    val oldValue = get(key)
    if (!predicate(key, oldValue)) return oldValue
    val newValue = mappingFunction(key, oldValue)
    if (newValue == oldValue) return newValue
    if (newValue != null) put(key, newValue)
    else if (oldValue != null) remove(key)
    return newValue
    }
    functions as inputs

    View Slide

  141. inline fun MutableMap.computeIf(key: K,
    predicate: (K, V?) -> Boolean,
    mappingFunction: (K, V?) -> V?): V? {
    val oldValue = get(key)
    if (!predicate(key, oldValue)) return oldValue
    val newValue = mappingFunction(key, oldValue)
    if (newValue == oldValue) return newValue
    if (newValue != null) put(key, newValue)
    else if (oldValue != null) remove(key)
    return newValue
    }
    all mutability hidden inside

    View Slide

  142. inline fun MutableMap.computeIf(key: K,
    predicate: (K, V?) -> Boolean,
    mappingFunction: (K, V?) -> V?): V? {
    val oldValue = get(key)
    if (!predicate(key, oldValue)) return oldValue
    val newValue = mappingFunction(key, oldValue)
    if (newValue == oldValue) return newValue
    if (newValue != null) put(key, newValue)
    else if (oldValue != null) remove(key)
    return newValue
    }
    blending programming paradigms

    View Slide

  143. cachedConfigs.computeIf(
    "KittiesOnDemandFeature",
    { key, previous -> previous?.json != kittyJson },
    { key, previous -> FeatureConfig.from(kittyJson) }
    )

    View Slide

  144. THANK YOU!
    SPEAKERDECK.COM/QUEENCODEMONKEY
    YOUTUBE.COM/ANDROIDDIALOGS
    RANDOMLYTYPING.COM
    HUYEN TUE DAO
    @QUEENCODEMONKEY

    View Slide

  145. val result = x + y
    computation

    View Slide

  146. val result = x + y
    action

    View Slide

  147. REFERENCES
    147
    Wikipedia: Functional Programming | wikipedia.org/wiki/Functional_programming
    Functional Programming | https://wiki.haskell.org/Functional_programming
    What Is Functional Programming? | blog.jenkster.com/2015/12/what-is-functional-programming.html | @krisajenkins
    An introduction to functional programming | codewords.recurse.com/issues/one/an-introduction-to-functional-programming |
    @maryrosecook
    Imperative vs. Declarative Programming | https://tylermcginnis.com/imperative-vs-declarative-programming/ | @tylermcginnis
    Imperative Style | http://blog.agiledeveloper.com/2015/07/the-imperative-style.html | @venkat_s
    Declarative Style | http://blog.agiledeveloper.com/2015/07/the-declarative-style.html | @venkat_s
    Functional Style | http://blog.agiledeveloper.com/2015/08/the-functional-style.html | @venkat_s
    Benefits of Pure Functions: Offer Referential Transparency | blog.agiledeveloper.com/2016/01/benefits-of-pure-functions-offer.html |
    @venkat_s
    Functional Programming Favors Expressions over Statements | http://blog.agiledeveloper.com/2015/08/functional-programming-
    favors.html | @venkat_s
    What is function programming? | https://www.quora.com/What-is-functional-programming

    View Slide

  148. REFERENCES
    148
    Kotlin in Action | manning.com/books/kotlin-in-action
    WikiWikiWeb | wiki.c2.com/
    Why Functional Programming Matters | https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf | John Hughes, The
    University, Glasgow
    Kotlin purity and function memoization | https://medium.com/@JorgeCastilloPr/kotlin-purity-and-function-memoization-
    b12ab35d70a5
    Kotlin Functional Programming: Does it make sense? | medium.com/@JorgeCastilloPr/kotlin-functional-programming-does-it-make-
    sense-36ad07e6bacf | @JorgeCastilloPr
    Functional, Declarative, Imperative Programming [closed] | https://stackoverflow.com/questions/602444/functional-declarative-and-
    imperative-programming
    What are monads in functional programming and why are they useful? | https://www.quora.com/What-are-monads-in-functional-
    programming-and-why-are-they-useful-Are-they-a-generic-solution-to-the-problem-of-state-in-FP-or-Haskell-specific-Are-they-
    specific-to-Haskell-or-are-they-encountered-in-other-FP-languages

    View Slide