Functions

Outline

  • Introduction Functions

  • Higher-order Functions and Lambdas

  • Inline Functions

What is Function?

In Kotlin, functions are first-class citizen.

It means that functions can be assigned to the variables, passed as an arguments or returned from another function.

How many kinds of function?

  • Member functions

  • Tail recursive functions

  • Generic functions

  • Extension functions

  • Higher-order functions and lambdas

  • Inline functions

Member Functions

class Sample() {
    fun foo() { print("Foo") }
}

Tail Recursive Functions

fun recursiveFactorial(n: Long) : Long {
    return if (n <= 1) {
        n
    } else {
        n * recursiveFactorial(n - 1)
    }
}

Generic Functions

fun <T> singletonList(item: T): List<T> { 
	/*...*/ 
}

Extension Functions

fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

Higher-order Functions

fun runTransformation(f: (String, Int) -> String): String {
    return f("hello", 3)
}

Inline Functions

public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

What is higher-order function

A higher-order function is a function that takes functions as parameters, or returns a function.

Collection API

  • foreach

  • filter

  • map

  • reduce

  • flatmap

foreach

val people = listOf(Person("Alice", 29), Person("Bob", 31))
people.foreach{
    print(it.name) // output : Alice Bob
}

foreach

filter

val people = listOf(Person("Alice", 29), Person("Bob", 31))
val pList = people.filter{
    it.age > 30
}
print(pList) // output: [Person(name=Bob, age=31)]

filter

map

val people = listOf(Person("Alice", 29), Person("Bob", 31))
val pList = people.map{
    it.name
}
print(pList) // output: [Alice, Bob]

map

reduce

val people = listOf(Person("Alice", 29), Person("Bob", 31))
val pList = people.map{
    it.name
}.reduce{ acc, s-> 
    "$acc,$s"
}
print(pList) // output: Alice,Bob

reduce

,

,

,

flatmap

val people = listOf(
    Person("Alice", 29, arrayListOf("A", "B")), 
    Person("Bob", 31, arrayListOf("C", "D")))
val books = people.flatmap{
    it.bookList
}
print(books) // output: [A, B, C, D]

flatmap

[

[

[

]

]

]

Eagerly vs Lazy

  • These Functions create intermediate collections eagerly, meaning the intermediate result of each step is stored in a temporary list.

  • Sequences give you an alternative way to perform such computations that avoids the creation of intermediate temporary objects.

Eagerly

people.map(People::name).fliter{ it.startWith("A")}

Sequences

people.asSequence()
  .map(Person::name)
  .filter { it.startsWith("A") }
  .toList()

Switch Position

people.filter{ it.name.startWith("A")}.map(People::name)

//better than

people.map(People::name).filter{ it.name.startWith("A")}

What is Lambda

Lambda expression or simply lambda is an anonymous function

Single Abstract Method(SAM)

/* Java */
public interface OnClickListener{ 
	void onClick(View v);
}

/* Java */
public class Button {
	public void setOnClickListener(OnClickListener l) { ... }
}

button.setOnClickListener(new OnClickListener() {
	@Override
    public void onClick(View v) {
  		...
  	}
}

/* kotlin */
button.setOnClickListener { view -> ... }

Decompile function

fun sum(a: Int, b: Int, lambda: (result: Int) -> Unit): Int {
    val r = a + b
    lambda.invoke(r)
    return r
}

fun main(args: Array<String>) {
    sum(1, 2) { println("Result is: $it") }
}

//decompile
public static final void main(@NotNull String[] args) {
   //...
   sum(1, 2, (Function1)null.INSTANCE);
}

Decompile inline function

inline fun sum(a: Int, b: Int, lambda: (result: Int) -> Unit): Int {
    val r = a + b
    lambda.invoke(r)
    return r
}

fun main(args: Array<String>) {
    sum(1, 2) { println("Result is: $it") }
}

//decompile
public static final void main(@NotNull String[] args) {
   //...
   byte a$iv = 1;
   int b$iv = 2;
   int r$iv = a$iv + b$iv;
   String var9 = "Result is: " + r$iv;
   System.out.println(var9);
}

Returns and Jumps

  • return: By default returns from the nearest enclosing function or anonymous function.

  • break: Terminates the nearest enclosing loop.

  • continue: Proceeds to the next step of the nearest enclosing loop.

break and continue

loop@ for (i in 1..100) {
    for (j in 1..100) {
        if (...) break@loop
    }
}

loop@ for (i in 1..100) {
    for (j in 1..100) {
        if (...) continue@loop
    }
}

return outer function

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
    	// non-local return directly to the caller of foo()
        if (it == 3) return 
        print(it)
    }
    println("this point is unreachable")
}

output: 12

return lambda function

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach lit@{
        // local return to the caller of the lambda
        if (it == 3) return@lit 
        print(it)
    }
    print(" done with explicit label")
}

output: 1245 done with explicit label

return lambda function

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
    	//// local return to the caller of the lambda
        if (it == 3) return@forEach 
        print(it)
    }
    print(" done with implicit label")
}

output: 1245 done with explicit label

return anonymous function

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
    	// local return to the caller of the anonymous fun
        if (value == 3) return  
        print(value)
    })
    print(" done with anonymous function")
}

output: 1245 done with anonymous function

return nesting lambda function

fun foo() {
    run loop@{
        listOf(1, 2, 3, 4, 5).forEach {
            // non-local return from the lambda passed to run
            if (it == 3) return@loop 
            print(it)
        }
    }
    print(" done with nested loop")
}

output: 12 done with nested loop

return 1 at label

return@a 1

means "return 1 at label @a" and not "return a labeled expression (@a 1)".

Thank you.

Made with Slides.com