Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

@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

Slide 5

Slide 5 text

@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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

@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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

@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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

@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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

@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

Slide 18

Slide 18 text

@TTGonda IMMUTABILITY class Burger(var type: String)

Slide 19

Slide 19 text

@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; } }

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

@TTGonda IMMUTABILITY class Burger(val type: String)

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

@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; } }

Slide 29

Slide 29 text

@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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

@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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

@TTGonda ERROR HANDLING deliver(burger)

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

@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) }

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

@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() } } } }

Slide 47

Slide 47 text

@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() } } } }

Slide 48

Slide 48 text

@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() } } } }

Slide 49

Slide 49 text

@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() } } } }

Slide 50

Slide 50 text

@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() } } } }

Slide 51

Slide 51 text

@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

Slide 52

Slide 52 text

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