Functional Programming in Android

Teagan Glenn

      Teagan42

Senior Software Engineer

Aetna

Functional Programming

What is it?

Side-effect Free Coding

  • No reliance on data outside function
    • Operates only on the arguments passed in
  • Does not change data outside of function
    • Data passed in is not mutated
    • Data returned is always a new instance

Some Definitions

  • Pure Function - Given the same input, will always return the same output and produce no side-effects
  • First Class Functions - Functions are treated no different than variables; can be passed as arguments, returned from other functions, etc.
  • Higher Order Function - A function that accepts a function as an argument and/or a function that returns another function 
  • Map - Applies a given function to all elements of a collection, returning a list of the results
  • Reduce/Fold - Acts as an accumulator for a collection; example: sum of a collection of integers
  • Curry - A function that accepts fewer arguments than expected, returning a function that accepts the remaining arguments

Kotlin

The Basics

Variables & Fields

  • val - A variable that can't change during runtime (i.e. Java final)
  • var - A variable that may change during runtime
  • lateinit - A variable that is not initialized inline, but will be assigned before use, the type cannot be Nullable
  • const val - Compile time constant

Constructors

  • Primary Constructor
    • Declared inline with class header
    • Class fields are defined using var or val
  • Secondary Constructor
    • Declared in the class body
    • Class fields must be defined in class body
  • Initialization Block
    • Declared in the class body
    • Used to perform logic on object construction

Null

  • Only data types with a ? suffix can be nullable
    • Nullable String: var myString: String?
    • Non-nullable String: var myString: String
  • Use the Safe Call Operator (?.) to perform null checks on function and property chains
    • If any part of the chain is null, the result of the operation is null
  • Elvis Operator (?:) coalesces to the right operand if the left operand is null

Lambda

  • Is not declared, but is passed immediately as an expression
  • Should be expressive, not narrative
    • Atomic (Single Purpose)
    • Short and Sweet
  • Should be pure

Kotlin 

Standard Library

let

  • Transforms
  • Passes operant as it
  • Performs an expression block
  • Returns the result of the last item of the expression block

apply

  • Doesn't transform
  • Passes operant as this
  • Performs an expression block
  • Returns the instance that was passed in

Examples

/*
 * Kotlin let
 */
fun setActivityTitle(title: String?): Fragment? = 
    title?.let { 
        activity?.title = it
        this
    }

// With parameter name override
fun setActivityTitle(title: String?): Fragment? =
        title?.let { newTitle ->
            {
                activity?.title = newTitle
                this
            }() // Since it's a block, we need to evaluate it
        }

/*
 * Kotlin apply
 */
fun setActivityTitle(title: String?) = title?.apply { activity?.title = this }

run

  • Transforms
  • Passes operant as this
  • Performs an expression block
  • Returns the result of the last item of the expression block

also

  • Doesn't transform
  • Passes operant as this
  • Performs an expression block
  • Returns the instance that was passed in

Examples

/*
 * Kotlin run
 */
fun setActivityTitle(title: String?) = title?.run { activity?.title = this }

/*
 * Kotlin also
 */

fun setActivityTitle(title: String?): String? =
        title?.also { activity?.title = it }

// With parameter name override
fun setActivityTitle(title: String?): String? =
        title?.also { newTitle -> activity?.title = newTitle }


with

Syntactic sugar for run without an operant

use

Safely closes the operant upon completion of the block expression, regardless of exception

  • InputStreams
  • OutputStreams
  • Readers

Examples

/*
 * Kotlin with
 */
override fun onViewCreated() {
    with(my_text_view) {
        text = "My Default Text"
        setOnClickListener = textClickListener
        setOn
    }
}

/*
 * Kotlin use
 */
fun getTestData(context: Context, gson: Gson, jsonAssetName: String) =
    context.resources.assets.open().use {
        gson.fromJson(InputStreamConverter.getInputStreamAsString(this), SomeDataType::class.java)
    }

Kotlin

Extension Functions

infix

  • Allows invocation without . and ()
  • Can only accept one parameter
  • Can be thought of as operators

inline

  • When using higher order functions, each function is an object, with reference to each argument, held in memory
  • Inline functions do not instantiate each function, instead copying the code outside of the block invocation, reducing memory usage but increasing bytecode size

Examples

infix fun Int.mod(divisor: Int): Int = this % divisor

fun calculateChange(amount: Int) = amount mod 100

//--------------------\\

inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> Unit) {
    val fragmentTransaction = beginTransaction()
    fragmentTransaction.func()
    fragmentTransaction.commit()
}

fun setFragment(fragment: Fragment) {
    supportFragmentManager.inTransaction {
        replace(contentViewId, fragment, fragment::class.simpleName)
        addToBackStack.ifTrue { addToBackStack(fragment::class.simpleName) }
    }
}

//--------------------\\

fun String?.toUri(): Uri? =
    if (this == null) null
    else try {
        Uri.parse(this)
    } catch (e: Exception) {
        Timber.e(e)
        null
    }

fun goToUrl(address: String?) = startActivity(Intent(Intent.ACTION_VIEW, address?.toUri()))

Kotlin

Things to Remember

Adds to Compilation Time

Can Increase APK Size

Can Increase Memory Footprint

If We Use Kotlin

Use Functional Programming

Further Reading

Made with Slides.com