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

Introduction to Functional-Reactive Programming v2

Introduction to Functional-Reactive Programming v2

v2.0

Grzegorz Dyrda

September 26, 2018
Tweet

More Decks by Grzegorz Dyrda

Other Decks in Programming

Transcript

  1. Grzegorz Dyrda
    Geeky Devs Studio
    Introduction to
    Functional-Reactive
    Programming

    View Slide

  2. Functional-Reactive
    Programming

    View Slide

  3. Functional-Reactive
    Programming
    Why?

    View Slide

  4. Why?
    • Java 9 + Reactive Streams (JEP 266)
    • Spring WebFlux, Eclipse Vert.x
    • Angular, Cycle.js, React (Native)
    • Android Architecture Components,
    Room, Retrofit… Airbnb MvRx

    View Slide

  5. Functional-Reactive

    View Slide

  6. Functional + Reactive

    View Slide

  7. Functional
    Part 1:

    View Slide

  8. You cannot understand
    Functional-Reactive programming,
    if you don’t understand
    Functional programming.

    View Slide

  9. What is Functional Programming?

    View Slide

  10. Functional Programming
    Programming style in which we avoid
    sharing state and data mutation,
    in favor of composing functions and
    passing data from one to another.

    View Slide

  11. Functional Programming
    …is about moving from

    the imperative

    to declarative style.

    View Slide

  12. The world’s most popular
    functional language is…
    Excel

    View Slide

  13. =IF(A6="", IF(C5<>"", C5, IFERROR(MATCH("?*", A6:$A$20, 0)-1,
    ROWS(A6:$A$20))&" in "&VLOOKUP(A5,$H$6:$I$8, 2, 0)), "")
    Excel
    =IF(MONTH($C$3)<>MONTH($C$3-(WEEKDAY($C$3;1)-($A$1-1))-
    IF((WEEKDAY($C$3;1)-($A$1-1))<=0;7;0)+(ROW(F7)-J3-
    ROW($D$6))*7+(COLUMN(F7)-COLUMN($D$6)+1));"";$C$3-
    (WEEKDAY($C$3;1)-($A$1-1))-IF((WEEKDAY($C$3;1)-
    ($A$1-1))<=0;7;0)+(ROW(F7)-J3-ROW($D$6))*7+(COLUMN(F7)-
    COLUMN($D$6)+1))

    View Slide

  14. Language Support

    View Slide

  15. • Functions as first-class citizens
    • Higher-order functions
    • Lambda expressions
    • Immutable data types
    • Functions are closures
    Language Support
    JAVA 8+
    APPROVED

    View Slide

  16. Example

    View Slide

  17. Client says:
    “Make a sum of all our prices

    that are higher than $20,

    discounted by 10%”
    Example

    View Slide

  18. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example

    View Slide

  19. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    var sum = 0.0
    for (var i = 0; i <= prices.size; i++) {

    if (price[i] > 20) {

    sum += price[i] * 0.9

    }}

    }}
    val prices = listOf(20, 12, 15, 21, 25, 28, 30)

    View Slide

  20. var sum = 0.0
    for (var i = 0; i < prices.size; i++) {

    if (price[i] > 20) {

    sum += price[i] * 0.9

    }}

    }}
    Example
    val prices = listOf(20, 12, 15, 21, 25, 28, 30)

    View Slide

  21. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    var sum = 0.0
    for (price in prices) {

    if (price > 20) {

    sum += price * 0.9

    }}

    }}

    View Slide

  22. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()
    var sum = 0.0
    for (price in prices) {

    if (price > 20) {

    sum += price * 0.9

    }}

    }}

    View Slide

  23. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()

    View Slide

  24. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()

    View Slide

  25. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()

    View Slide

  26. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()

    View Slide

  27. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()

    View Slide

  28. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()
    Important:
    1. No import = stdlib
    2. Cross-platform

    View Slide

  29. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()

    View Slide

  30. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()
    // Returns list containing only elements matching [predicate]
    fun filter(predicate: (T) -> Boolean): List

    View Slide

  31. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()
    // Returns list containing only elements matching [predicate]
    fun filter(predicate: (T) -> Boolean): List

    View Slide

  32. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    // Returns list containing elements transformed by [transform]
    fun map(transform: (T) -> R): List
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()

    View Slide

  33. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    // Returns list containing elements transformed by [transform]
    fun map(transform: (T) -> R): List
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()

    View Slide

  34. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()
    Single, consistent, higher-level API.
    More readable & closer to the Business Intent

    View Slide

  35. val prices = listOf(20, 12, 15, 21, 25, 28, 30)
    Example
    val sum = prices

    .filter { price -> price > 20 }

    .map { price -> price * 0.9 }

    .sum()
    var sum = 0.0
    for (price in prices) {

    if (price > 20) {

    sum += price * 0.9

    }}

    }}

    View Slide

  36. Another
    Example

    View Slide

  37. You’re a Blog admin:
    “Calculate average blogpost length
    of all your blog’s Users
    that speak Polish”
    Example

    View Slide

  38. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example

    View Slide

  39. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val users = db.getAllUsers()

    View Slide

  40. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = ???
    val users = db.getAllUsers()

    View Slide

  41. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users
    val users = db.getAllUsers()

    View Slide

  42. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { ??? }}
    val users = db.getAllUsers()

    View Slide

  43. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }}
    val users = db.getAllUsers()

    View Slide

  44. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .map { ??? }}
    val users = db.getAllUsers()

    View Slide

  45. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .map { user -> user.posts }}
    val users = db.getAllUsers()

    View Slide

  46. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .map { user -> user.posts }
    // Return type is: List>
    // But we need: List
    val users = db.getAllUsers()

    View Slide

  47. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .map { user -> user.posts }
    val users = db.getAllUsers()

    View Slide

  48. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }
    val users = db.getAllUsers()

    View Slide

  49. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }
    // Returns a single list with all elements yielded from
    // [transform] invoked on on each element of original collection.
    fun flatMap(transform: (T) -> Iterable): List
    val users = db.getAllUsers()

    View Slide

  50. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }
    // Returns a single list with all elements yielded from
    // [transform] invoked on on each element of original collection.
    fun flatMap(transform: (T) -> Iterable): List
    val users = db.getAllUsers()

    View Slide

  51. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }
    // Returns a single list with all elements yielded from
    // [transform] invoked on on each element of original collection.
    fun flatMap(transform: (T) -> Iterable): List
    val users = db.getAllUsers()

    View Slide

  52. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }
    val users = db.getAllUsers()

    View Slide

  53. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }

    .map { ??? }}
    val users = db.getAllUsers()

    View Slide

  54. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }}
    val users = db.getAllUsers()

    View Slide

  55. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }

    .average()
    val users = db.getAllUsers()

    View Slide

  56. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }

    .average()
    val users = db.getAllUsers()
    // Easy to maintain and modify

    View Slide

  57. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .filter { user -> user.language == "PL" }

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }

    .average()
    val users = db.getAllUsers()

    View Slide

  58. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .take(100)

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }

    .average()
    val users = db.getAllUsers()

    View Slide

  59. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .take(100)

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }

    .average()
    val users = db.getAllUsers()

    View Slide

  60. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .take(100)

    .flatMap { user -> user.posts }
    .map { post -> post.body.length }
    .count()
    val users = db.getAllUsers()

    View Slide

  61. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .take(100)

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }

    .reduce { acc, length -> acc + length }
    val users = db.getAllUsers()

    View Slide

  62. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .take(100)

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }

    .reduce { acc, length -> acc + length }}
    val users = db.getAllUsers()
    // Returns a single value computed by accumulating values
    // returned from applying [operation] to each element.
    fun reduce(operation: (acc: S, T) -> S): S

    View Slide

  63. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .take(100)

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }

    .reduce { acc, length -> acc + length }}
    val users = db.getAllUsers()
    // Returns a single value computed by accumulating values
    // returned from applying [operation] to each element.
    fun reduce(operation: (acc: S, T) -> S): S

    View Slide

  64. data class Post(val title: String, val body: String)

    data class User(val language: String, val posts: List)
    Example
    val avgPolishPostLength = users

    .take(100)

    .flatMap { user -> user.posts }

    .map { post -> post.body.length }

    .fold(0) { acc, _ -> acc + 1 }}
    val users = db.getAllUsers()
    // Accumulates value starting with [initial] and applying
    // [operation] to current accumulator value and each element.
    fun fold(initial: R, operation: (acc: R, T) -> R): R

    View Slide

  65. Benefits

    View Slide

  66. • No explicit mutation, reassignment,
    iteration etc. = less error prone
    • Low-level details controlled by the library
    = may be optimized under the hood
    • More expressive, more readable
    • Easy to enhance & modify the logic
    • Closer to the business intent
    Benefits

    View Slide

  67. Functional
    -vs-
    Object-Oriented

    View Slide

  68. Functional
    -vs-
    Object-Oriented

    View Slide

  69. Functional
    +
    Object-Oriented

    View Slide

  70. // Returns list containing only elements matching [predicate]
    fun filter(predicate: (T) -> Boolean): List
    // Returns list containing elements transformed by [transform]
    fun map(transform: (T) -> R): List
    // Flattens nested lists into single list
    fun flatMap(transform: (T) -> Iterable): List
    // Accumulates value by applying [operation]
    fun reduce(operation: (acc: S, T) -> S): S
    // Accumulates value, starting with [initial]
    fun fold(initial: R, operation: (acc: R, T) -> R): R
    Common Specialized Functions

    View Slide

  71. View Slide

  72. View Slide

  73. Functional…

    View Slide

  74. Functional + Reactive

    View Slide

  75. Reactive
    Part 2:

    View Slide

  76. What does is mean
    to be “Reactive”?

    View Slide

  77. var a = 1
    var b = 2
    var c = a + b
    print("c = $c")
    What does is mean
    to be “Reactive”?
    // ???

    View Slide

  78. var a = 1
    var b = 2
    var c = a + b
    print("c = $c")
    What does is mean
    to be “Reactive”?
    // c = 3

    View Slide

  79. var a = 1
    var b = 2
    var c = a + b
    a = 2
    print("c = $c")
    What does is mean
    to be “Reactive”?
    // ???

    View Slide

  80. var a = 1
    var b = 2
    var c = a + b
    a = 2
    print("c = $c")
    What does is mean
    to be “Reactive”?
    // c = 3

    View Slide

  81. The world’s most popular
    reactive system is…
    Excel

    View Slide

  82. Excel

    View Slide

  83. What is Reactive Programming?

    View Slide

  84. Reactive Programming
    Programming with

    Asynchronous Event Streams

    View Slide

  85. Reactive Programming
    Programming with

    Asynchronous Event Streams

    View Slide

  86. Observer Pattern
    on Steroids
    Reactive Programming

    View Slide

  87. Observer Pattern
    on Functional Steroids
    Reactive Programming

    View Slide

  88. 1 5 12 3 7 4
    This can be anything: Number,
    Object, Blog Post etc.

    View Slide

  89. 1
    filter(x > 4)
    5 12 3 7 4

    View Slide

  90. 1
    filter(x > 4)
    5 12 7
    5 12 3 7 4

    View Slide

  91. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    5 12 3 7 4

    View Slide

  92. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    7 14 9
    5 12 3 7 4

    View Slide

  93. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    7 14 9
    5 12 3 7 4
    So far everything was…

    Synchronous

    View Slide

  94. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    7 14 9
    5 12 3 7 4
    Introducing…

    Time

    View Slide

  95. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    7 14 9
    5 12 3 7 4

    View Slide

  96. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    7 14 9
    5 12 3 7 4

    View Slide

  97. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    7 14 9
    5 12 3 7 4

    View Slide

  98. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    7 14 9
    5 12 3 7 4

    View Slide

  99. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    7 14 9
    5 12 3 7 4

    View Slide

  100. 1
    filter(x > 4)
    5 12 7
    map(x + 2)
    7 14 9
    5 12 3 7 4

    View Slide

  101. 5 12 7
    map(x + 2)
    (Asynchronous Event)
    Stream
    Events
    Operator

    View Slide

  102. 5 12 7
    map(x + 2)
    Stream
    Events
    Infinite
    Operator

    View Slide

  103. 5 12 7
    map(x + 2)
    Stream
    Events
    Error
    Operator

    View Slide

  104. 5 12 7
    map(x + 2)
    Stream
    Events
    Complete
    Operator

    View Slide

  105. Implementation

    View Slide

  106. Akka
    Reactor
    Reactive Extensions
    Vert.x
    xstream
    Implementation

    View Slide

  107. Akka
    Reactor
    Reactive Extensions
    Vert.x
    xstream
    Implementation

    View Slide

  108. Rx
    Implementation

    View Slide

  109. • RxJava
    • RxJS
    • Rx.NET
    • RxScala
    • RxClojure
    • RxCpp
    Implementation
    • RxPython
    • RxGo
    • RxKotlin
    • RxSwift
    • RxPHP
    • RxDart

    View Slide

  110. Stream

    View Slide

  111. Stream
    Observable

    View Slide

  112. Stream
    Observable
    List
    -vs-

    View Slide

  113. Creating a Stream

    View Slide

  114. Observable.just(1)
    Observable.just(true)
    Observable.just(user)
    Observable.just("one", "two", "three")
    Creating a Stream
    Observable.fromIterable(users)
    Observable.fromArray(usersArray)
    Observable.fromCallable(this::sendRequest)
    Observable.fromFuture(future)
    Observable.defer(...)
    Observable.create(...)

    View Slide

  115. Observing a Stream

    View Slide

  116. Observable.just(1))
    Observing a Stream
    .subscribe { item ->

    print("Item = $item")

    }}
    // Item = 1

    View Slide

  117. Observing a Stream
    // Subscribes the given Observer to this Observable instance.
    fun subscribe(observer: Observer): Unit
    interface Observer {

    fun onNext(t: T)

    fun onError(e: Throwable)

    fun onComplete()
    ...

    }}
    // Subscribes to an ObservableSource and provides callbacks.
    fun subscribe(onNext: (T) -> Unit,
    onError: (Throwable) -> Unit,
    onComplete: () -> Unit): Unit

    View Slide

  118. Observable.just(1))
    Observing a Stream
    .subscribe { item ->

    print("Item = $item")

    }}
    // Item = 1

    View Slide

  119. Observable.just(true))
    .subscribe { item ->

    print("Item = $item")

    }}
    // Item = true
    Observing a Stream

    View Slide

  120. Observable.just(user))
    .subscribe { item ->

    print("Item = $item")

    }}
    // Item = User(language="PL",posts=...)
    Observing a Stream

    View Slide

  121. Observable.just("one", "two", "three")
    .subscribe { item ->

    print("Item = $item")

    }}
    // Item = one
    // Item = two
    // Item = three
    Observing a Stream

    View Slide

  122. Observable.fromIterable(users))
    .subscribe { item ->

    print("Item = $item")

    }}
    // Item = User(language="PL",posts=...)
    // Item = User(language="EN",posts=...)
    // Item = User(language="PL",posts=...)
    // Item = User(language="PL",posts=...)
    ...
    Observing a Stream

    View Slide

  123. Observable.fromIterable(users))
    .subscribe { item ->

    print("Item = $item")

    }}
    // Item = User(language="PL",posts=...)
    // Item = User(language="EN",posts=...)
    // Item = User(language="PL",posts=...)
    // Item = User(language="PL",posts=...)
    ...
    Where are my Steroids?
    Observing a Stream

    View Slide

  124. Transforming a Stream

    View Slide

  125. Observable.just("5", "8", "3", "7")
    .subscribe { item ->

    print("Item = $item")

    }}
    Transforming a Stream

    View Slide

  126. Observable.just("5", "8", "3", "7")
    .map(String::toInt)
    .subscribe { item ->

    print("Item = $item")

    }}
    Transforming a Stream

    View Slide

  127. Observable.just("5", "8", "3", "7")
    .map(String::toInt)
    .filter { item -> item > 5 }
    .subscribe { item ->

    print("Item = $item")

    }}
    // Item = 8
    // Item = 7
    Transforming a Stream

    View Slide

  128. View Slide

  129. “There’s an App for that”
    Apple, 2009

    View Slide

  130. “There’s an Operator for that”
    Reactive Extensions, 2018

    View Slide

  131. ReactiveX Operators
    Creating:
    • create
    • defer
    • empty
    • error
    • fromArray
    • fromCallable
    • fromFuture
    • interval
    • just
    • …
    Transform/Filter:
    • buffer
    • flatMap
    • groupBy
    • map
    • scan
    • window
    • debounce
    • distinct
    • filter
    • …
    Combining:
    • combineLatest
    • withLatestFrom
    • merge
    • switch
    • zip
    Threading:
    • subscribeOn
    • observeOn
    • …

    View Slide

  132. Introducing Time

    View Slide

  133. Observable.interval(1, TimeUnit.SECONDS)
    Interval
    .subscribe { item ->

    print("Item = $item")

    }}
    //00:00: Item = 0
    //00:01: Item = 1
    //00:02: Item = 2
    //00:03: Item = 3
    //00:04: Item = 4
    //...

    View Slide

  134. Observable.interval(1, TimeUnit.SECONDS)
    Interval
    .map { item -> item * item }
    .subscribe { item ->

    print("Item = $item")

    }}

    View Slide

  135. Observable.interval(1, TimeUnit.SECONDS)
    Interval
    .map { item -> item * item }.
    .take(3)
    .subscribe { item ->

    print("Item = $item")

    }}
    //00:00: Item = 0
    //00:01: Item = 1
    //00:02: Item = 4

    View Slide

  136. // RxBinding
    RxView.clicks(button) // Observable
    .map { click -> 1 }
    .scan { acc, next -> acc + next }
    UI Events
    // Similar to reduce(), but accumulates values over time,
    // each time passing the result of [operation] downstream.
    fun scan(operation: (acc: T, T) -> T): Observable

    View Slide

  137. // RxBinding
    RxView.clicks(button) // Observable
    .map { click -> 1 }
    .scan { acc, next -> acc + next }
    UI Events
    .subscribe { count ->

    print("Count = $count")

    }
    // Count = 1
    // Count = 2
    // Count = 3
    // Count = 4
    // ...

    View Slide

  138. // Retrofit
    myService.getUsers() // Observable
    .map { user -> user.posts.size }
    .reduce { acc, next -> acc + next }
    Network Requests
    .subscribe { count ->

    print("Post count = $count")

    }
    // Post count = 120

    View Slide

  139. Threading

    View Slide

  140. fun fetchUser(): User { /* fetch from network */ }
    Threading
    Observable.fromCallable(this::fetchUser)
    .subscribe { user ->

    print("User = $user")

    }}
    // Error: Network on the Main Thread!

    View Slide

  141. fun fetchUser(): User { /* fetch from network */ }
    Threading
    Observable.fromCallable(this::fetchUser)
    .subscribe { user ->

    print("User = $user")

    }}
    .subscribeOn(Schedulers.io())

    View Slide

  142. fun fetchUser(): User { /* fetch from network */ }
    Threading
    Observable.fromCallable(this::fetchUser)
    .subscribe { user ->

    print("User = $user")

    }}
    .subscribeOn(Schedulers.io())

    View Slide

  143. fun fetchUser(): User { /* fetch from network */ }
    Threading
    Observable.fromCallable(this::fetchUser)
    .subscribe { user ->

    print("User = $user")

    }}
    .subscribeOn(Schedulers.io())

    View Slide

  144. fun fetchUser(): User { /* fetch from network */ }
    Threading
    Observable.fromCallable(this::fetchUser)
    .subscribeOn(Schedulers.io())
    .subscribe { user ->
    statusLabel.text = user.firstName

    }}
    // Error: Accessing UI from the background thread!

    View Slide

  145. fun fetchUser(): User { /* fetch from network */ }
    Threading
    .subscribe { user ->
    statusLabel.text = user.firstName

    }}
    Observable.fromCallable(this::fetchUser)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())

    View Slide

  146. fun fetchUser(): User { /* fetch from network */ }
    Threading
    .subscribe { user ->
    statusLabel.text = user.firstName

    }}
    Observable.fromCallable(this::fetchUser)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())

    View Slide

  147. fun fetchUser(): User { /* fetch from network */ }
    Threading
    .subscribe { user ->
    statusLabel.text = user.firstName

    }}
    Observable.fromCallable(this::fetchUser)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    // OK

    View Slide

  148. Combining Streams

    View Slide

  149. // Task: perform network request after each click
    Combining Streams
    // Return type: Observable>
    // But we want: Observable
    val buttonClicks = RxView.clicks(button)
    val userInfoRequest = myService.getUserInfo()
    buttonClicks
    .map { click -> myService.getUserInfo() }

    View Slide

  150. // Returns Observable that emits all items emitted by
    // Observables returned by [mapper].
    fun flatMap(mapper: (T) -> Observable): Observable
    buttonClicks
    .flatMap { click -> myService.getUserInfo() }
    val buttonClicks = RxView.clicks(button)
    val userInfoRequest = myService.getUserInfo()
    // Task: perform network request after each click
    Combining Streams

    View Slide

  151. .map { user -> user.firstName }
    .subscribe { firstName ->

    print("firstName = $firstName")

    }
    // firstName = John
    val buttonClicks = RxView.clicks(button)
    val userInfoRequest = myService.getUserInfo()
    buttonClicks
    .flatMap { click -> myService.getUserInfo() }
    // Task: perform network request after each click
    Combining Streams

    View Slide

  152. // Task: do the same thing on btn1 & btn2 click
    val btn1Clicks = RxView.clicks(button1)
    val btn2Clicks = RxView.clicks(button2)
    btn1Clicks
    .map { click -> "Click!" }
    .subscribe { msg ->

    print("msg = $msg")

    }}
    Combining Streams

    View Slide

  153. // Task: do the same thing on btn1 & btn2 click
    val btn1Clicks = RxView.clicks(button1)
    val btn2Clicks = RxView.clicks(button2)
    Observable.merge(btn1Clicks, btn2Clicks)
    .map { click -> "Click!" }
    .subscribe { msg ->

    print("msg = $msg")

    }}
    // Merges two (or more) Observables into a single one.
    fun merge(s1: Observable, s2: Observable): Observable
    Combining Streams

    View Slide

  154. Combining Streams

    View Slide

  155. Combining Streams

    View Slide

  156. Netflix

    View Slide

  157. Netflix

    View Slide

  158. Netflix

    View Slide

  159. Netflix

    View Slide

  160. Netflix

    View Slide

  161. Netflix

    View Slide

  162. Netflix

    View Slide

  163. Netflix

    View Slide

  164. Conclusions

    View Slide

  165. • FRP is great for composing/
    orchestrating multiple Event streams
    • “There’s an Operator for that”
    • Declarative Threading, Error handling,
    Cancellation of async tasks etc.
    • Do not overuse for simple tasks
    Conclusions

    View Slide

  166. How to Start?

    View Slide

  167. How to Start?
    • ReactiveX.io
    • github.com/ReactiveX
    • rxmarbles.com
    • geekydevs.com/rx

    View Slide

  168. Thank You

    View Slide

  169. Thank You
    Any questions?

    View Slide