$30 off During Our Annual Pro Sale. View Details »

Functional Android

Functional Android

For the most part, programming in Android has meant living in the imperative programming world. Recently, many aspects of functional programming have become standard with the adoption of Kotlin and RxJava. What does it mean to use functional paradigm properties in our Android code, and how can it help us? In this talk you’ll learn some of the fundamentals of functional programming, and what this might look like on Android.

Victoria Gonda

February 27, 2018
Tweet

More Decks by Victoria Gonda

Other Decks in Programming

Transcript

  1. FUNCTIONAL ANDROID
    Victoria Gonda
    @TTGonda
    Photo by taylor hernandez on Unsplash

    View Slide

  2. @TTGonda
    WHO AM I?
    ➤ Android Engineer at Buffer
    ➤ Author for Ray Wenderlich
    ➤ Chicago
    ➤ Dancer

    View Slide

  3. @TTGonda
    THANKS TO ANUP COWKUR
    ➤ His blog posts provided lots of help in the
    research of this topic.
    ➤ Functional Programming for Android
    Developers

    View Slide

  4. @TTGonda
    WHY FUNCTIONAL PROGRAMMING?
    ➤ We’re seeing an increase of the use of the
    paradigm (Kotlin, RxJava, Λrrow)
    ➤ Features can be used to write cleaner, more
    expressive code
    ➤ Simplifies concurrency
    ➤ Easier to test
    Photo by Jennifer Pallian on Unsplash

    View Slide

  5. @TTGonda
    WHAT IS FUNCTIONAL PROGRAMMING?
    ➤ Came from lambda calculus
    ➤ Mimics the evaluation of mathematical
    functions
    ➤ Easier to test
    ➤ Some key characteristics of FP
    ➤ Declarative
    ➤ Explicitness
    ➤ Concurrency
    ➤ Higher Order Functions
    ➤ Immutability
    Photo by Patrick Tomasso on Unsplash

    View Slide

  6. @TTGonda
    WHAT ARE WE GOING TO TALK ABOUT?
    ➤ Pure functions
    ➤ No side effects
    ➤ Ordering
    ➤ Immutability
    ➤ Concurrency
    ➤ Higher order functions
    ➤ Error handling

    View Slide

  7. @TTGonda
    PURE FUNCTIONS
    ➤ Always gives the same output for a given
    input
    ➤ Independent of the outside world
    ➤ No side effects
    ➤ Easy to test
    Photo by Toa Heftiba on Unsplash

    View Slide

  8. @TTGonda
    PURE FUNCTIONS
    fun blend(ingredients: List): Milkshake {
    return Milkshake(milk.get(), icecream.get(), ingredients)
    }

    View Slide

  9. @TTGonda
    PURE FUNCTIONS
    fun blend(milk: Milk, icecream: IceCream,
    ingredients: List): Milkshake {
    return Milkshake(milk, icecream, ingredients)
    }

    View Slide

  10. @TTGonda
    NO SIDE EFFECTS
    ➤ Don’t change anything outside
    ➤ Lessens the dependence on context
    ➤ Eliminates surprises
    ➤ You guessed it, easier to test
    Photo by Annie Shelmerdine on Unsplash

    View Slide

  11. @TTGonda
    NO SIDE EFFECTS
    fun blend(milk: Milk, icecream: IceCream,
    ingredients: List): Milkshake {
    return glasses.pop()
    .fill(Milkshake(milk, icecream, ingredients))
    }

    View Slide

  12. @TTGonda
    NO SIDE EFFECTS
    fun blend(glass: Glass, milk: Milk, icecream: IceCream,
    ingredients: List): Milkshake {
    return glass.fill(Milkshake(milk, icecream, ingredients))
    }

    View Slide

  13. @TTGonda
    ORDERING
    ➤ Things that can be executed in any order
    ➤ Something we get to do when we have pure
    functions
    ➤ This means they can also be concurrent!
    Photo by Gabriel Gurrola on Unsplash

    View Slide

  14. @TTGonda
    ORDERING
    makeToast()
    mixEggs()
    fryBacon()

    View Slide

  15. @TTGonda
    ORDERING
    fun makeToast() {
    cooks.pop()
    .prepare(Toast)
    }

    View Slide

  16. @TTGonda
    ORDERING
    fun makeToast(cook: Cook) {
    cook.prepare(Toast)
    }

    View Slide

  17. @TTGonda
    IMMUTABILITY
    ➤ No changing things
    ➤ Want something different, make a new one
    ➤ You know it won’t change on you
    ➤ Watch for mutable child objects
    Photo by Alireza Etemadi on Unsplash

    View Slide

  18. @TTGonda
    IMMUTABILITY
    class Burger(var type: String)

    View Slide

  19. @TTGonda
    IMMUTABILITY
    public class Burger {
    private String type;
    public Burger(String type) {
    this.type = type;
    }
    public final String getType() {
    return this.type;
    }
    public final void setType(String type) {
    this.type = type;
    }
    }

    View Slide

  20. @TTGonda
    IMMUTABILITY
    val burger = Burger("veggie")
    burger.type = "beef"

    View Slide

  21. @TTGonda
    IMMUTABILITY
    class Burger(val type: String)

    View Slide

  22. @TTGonda
    IMMUTABILITY
    final public class Burger {
    final private String type;
    public Burger(String type) {
    this.type = type;
    }
    public final String getType() {
    return this.type;
    }
    }

    View Slide

  23. @TTGonda
    IMMUTABILITY
    val burger = Burger("veggie")
    burger.type = "beef"

    View Slide

  24. @TTGonda
    IMMUTABILITY
    class Burger(var type: String?)
    if (burger.type != null)
    burger.type.length

    View Slide

  25. @TTGonda
    IMMUTABILITY
    class Burger(val type: String?)
    if (burger.type != null)
    burger.type.length

    View Slide

  26. @TTGonda
    IMMUTABILITY
    class Burger(var type: String, val toppings: MutableList)
    val burger = Burger("veggie", mutableListOf())
    burger.toppings.add("onion")

    View Slide

  27. @TTGonda
    IMMUTABILITY
    class Burger(var type: String, val toppings: List)
    val burger = Burger("veggie", listOf())

    View Slide

  28. @TTGonda
    IMMUTABILITY
    final public class Burger {
    final private String type;
    final private List toppings;
    public Burger(String type, List toppings) {
    /* ... */
    }
    public final String getType() { /* ... */ }
    public final List getToppings() {
    List toppingsCopy = new ArrayList<>();
    toppingsCopy.addAll(toppings);
    return toppingsCopy;
    }
    }

    View Slide

  29. @TTGonda
    CONCURRENCY
    ➤ We want concurrency, but it can be hard
    ➤ Using pure functions with no side effects
    and immutability helps
    ➤ We can do things on different threads,
    without worrying about unexpected
    behavior
    ➤ Locks aren’t required, so we don’t have to
    worry about deadlock
    Photo by ål nik on Unsplash

    View Slide

  30. @TTGonda
    CONCURRENCY
    fun addToppings(burger: Burger, toppings: List)
    : Observable {
    burger.toppings.addAll(toppings)
    return Observable.just(burger)
    .subscribeOn(kitchenThread)
    }

    View Slide

  31. @TTGonda
    CONCURRENCY
    Observable.merge(
    addToppings(burger, listOf("tomato")),
    addToppings(burger, listOf("lettuce")))
    .observeOn(deliveryThread)
    .subscribe { finishedBurger ->
    deliver(finishedBurger)
    }

    View Slide

  32. @TTGonda
    CONCURRENCY
    fun addToppings(burger: ImmutableBurger, toppings: List)
    : Observable? {
    val newBurger = burger.copy(toppings = toppings)
    return Observable.just(newBurger)
    .subscribeOn(kitchenThread)
    }

    View Slide

  33. @TTGonda
    HIGHER ORDER FUNCTIONS
    ➤ Functions as first class citizens
    ➤ Pass functions into a function
    ➤ Share logic the way you do an object
    ➤ Lose single abstract method interfaces
    Photo by Emmy Smith on Unsplash

    View Slide

  34. @TTGonda
    HIGHER ORDER FUNCTIONS
    fun makePotatoes(potatoes: Potatoes,
    cookPotatoes: (Potatoes) -> CookedPotatoes) {
    val cleanPotatoes = washAndPeelPotatoes(potatoes)
    val cookedPotatoes = cookPotatoes(cleanPotatoes)
    eatPotatoes(cookedPotatoes)
    }

    View Slide

  35. @TTGonda
    HIGHER ORDER FUNCTIONS
    makePotatoes(Potatoes(), ::fryPotatoes)
    makePotatoes(Potatoes()) {
    fryPotatoes(it)
    }
    makePotatoes(Potatoes(), {
    fryPotatoes(it)
    })
    makePotatoes(Potatoes(), { potatoes ->
    fryPotatoes(potatoes)
    })

    View Slide

  36. @TTGonda
    HIGHER ORDER FUNCTIONS
    makePotatoes(Potatoes(), ::fryPotatoes)
    makePotatoes(Potatoes(), ::bakePotatoes)
    makePotatoes(Potatoes(), ::boilEm)
    makePotatoes(Potatoes(), ::mashEm)
    makePotatoes(Potatoes(), ::stickEmInAStew)

    View Slide

  37. @TTGonda
    HIGHER ORDER FUNCTIONS
    val customer = Customer()
    customer.setOnFinishedEatingListener {
    clearDishes()
    bringCheck()
    }

    View Slide

  38. @TTGonda
    ERROR HANDLING
    ➤ Everything is a value or computation
    ➤ Avoiding unexpected states
    ➤ Errors are treated as values
    Photo by chuttersnap on Unsplash

    View Slide

  39. @TTGonda
    ERROR HANDLING
    deliver(burger)

    View Slide

  40. @TTGonda
    ERROR HANDLING
    try {
    deliver(burger)
    } catch (error: DroppedPlateException) {
    makeNew(burger)
    }

    View Slide

  41. @TTGonda
    ERROR HANDLING
    try {
    deliver(burger)
    deliver(pancakes)
    deliver(fries)
    deliver(hashbrowns)
    } catch (error: DroppedPlateException) {
    // ?????
    }

    View Slide

  42. @TTGonda
    ERROR HANDLING
    try {
    deliver(burger)
    } catch (error: DroppedPlateException) {
    makeNew(burger)
    }
    try {
    deliver(pancakes)
    } catch (error: DroppedPlateException) {
    makeNew(pancakes)
    }
    try {
    deliver(fries)
    } catch (error: DroppedPlateException) {
    makeNew(fries)
    }
    try {
    deliver(hashbrowns)
    } catch (error: DroppedPlateException) {
    makeNew(hashbrowns)
    }

    View Slide

  43. @TTGonda
    ERROR HANDLING
    val result = deliver(burger)
    if (!result.success) {
    makeNew(burger)
    }

    View Slide

  44. @TTGonda
    ERROR HANDLING
    if (!deliver(burger).success) {
    makeNew(burger)
    }

    View Slide

  45. @TTGonda
    TOOLS
    ➤ Kotlin programming language
    ➤ RxJava library
    ➤ Λrrow library
    Photo by Leti Kugler on Unsplash

    View Slide

  46. @TTGonda
    { previousState, result ->
    when (result) {
    is FoldersResult.GetLastState -> previousState
    is FoldersResult.LoadFoldersTask -> {
    when {
    result.status == TaskStatus.SUCCESS ->
    FoldersUiModel.FoldersLoaded(result.folders)
    result.status == TaskStatus.FAILURE ->
    FoldersUiModel.Failed
    result.status == TaskStatus.IN_FLIGHT ->
    FoldersUiModel.InProgress
    else -> FoldersUiModel.Idle()
    }
    }
    }
    }

    View Slide

  47. @TTGonda
    { previousState, result ->
    when (result) {
    is FoldersResult.GetLastState -> previousState
    is FoldersResult.LoadFoldersTask -> {
    when {
    result.status == TaskStatus.SUCCESS ->
    FoldersUiModel.FoldersLoaded(result.folders)
    result.status == TaskStatus.FAILURE ->
    FoldersUiModel.Failed
    result.status == TaskStatus.IN_FLIGHT ->
    FoldersUiModel.InProgress
    else -> FoldersUiModel.Idle()
    }
    }
    }
    }

    View Slide

  48. @TTGonda
    { previousState, result ->
    when (result) {
    is FoldersResult.GetLastState -> previousState
    is FoldersResult.LoadFoldersTask -> {
    when {
    result.status == TaskStatus.SUCCESS ->
    FoldersUiModel.FoldersLoaded(result.folders)
    result.status == TaskStatus.FAILURE ->
    FoldersUiModel.Failed
    result.status == TaskStatus.IN_FLIGHT ->
    FoldersUiModel.InProgress
    else -> FoldersUiModel.Idle()
    }
    }
    }
    }

    View Slide

  49. @TTGonda
    { previousState, result ->
    when (result) {
    is FoldersResult.GetLastState -> previousState
    is FoldersResult.LoadFoldersTask -> {
    when {
    result.status == TaskStatus.SUCCESS ->
    FoldersUiModel.FoldersLoaded(result.folders)
    result.status == TaskStatus.FAILURE ->
    FoldersUiModel.Failed
    result.status == TaskStatus.IN_FLIGHT ->
    FoldersUiModel.InProgress
    else -> FoldersUiModel.Idle()
    }
    }
    }
    }

    View Slide

  50. @TTGonda
    { previousState, result ->
    when (result) {
    is FoldersResult.GetLastState -> previousState
    is FoldersResult.LoadFoldersTask -> {
    when {
    result.status == TaskStatus.SUCCESS ->
    FoldersUiModel.FoldersLoaded(result.folders)
    result.status == TaskStatus.FAILURE ->
    FoldersUiModel.Failed
    result.status == TaskStatus.IN_FLIGHT ->
    FoldersUiModel.InProgress
    else -> FoldersUiModel.Idle()
    }
    }
    }
    }

    View Slide

  51. @TTGonda
    RESOURCES
    ➤ Functional Programming for Android Developers by Anup Cowkur
    ➤ Functional Reactive Programming with RxJava by Francisco González
    ➤ Functional Programming in Kotlin with Arrow by Jorge Castillo on Caster.io

    View Slide

  52. THANKS!
    Victoria Gonda
    @TTGonda
    Photo by taylor hernandez on Unsplash

    View Slide