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

6. The Power of Inline [kotlin-workshop]

6. The Power of Inline [kotlin-workshop]

Part of https://github.com/jetBrains/kotlin-workshop.

Covers:
- Useful one-line library functions
- inline
- Reified Generics
- Collections vs Sequences

C6997ce411091d4a51ea3caa2109c0b0?s=128

Svetlana Isakova

November 01, 2017
Tweet

Transcript

  1. The power of inline

  2. Inlining Useful library functions Collections vs Sequences Agenda

  3. Under the Hood No performance overhead Lambdas can be inlined

  4. How inlining works? Why inline?..

  5. Useful library functions

  6. Useful library functions run, let, takeIf, takeUnless, repeat

  7. run function val foo = run { println("Calculating foo...") "foo"

    } runs the block of code (lambda) and returns the last expression as the result
  8. let function fun getEmail(): String? val email = getEmail() if

    (email != null) sendEmailTo(email) email?.let { e -> sendEmailTo(e) } getEmail()?.let { sendEmailTo(it) } allows to check the argument for being non-null, not only the receiver
  9. takeIf function val number = 42 number.takeIf { it >

    10 } // 42 val other = 2 other.takeIf { n -> n > 10 } // null returns the receiver object if it satisfies the given predicate, otherwise returns null
  10. takeUnless function val number = 42 number.takeUnless { it >

    10 } // null val other = 2 other.takeUnless { it > 10 } // 2 returns the receiver object if it does not satisfy the given predicate, otherwise returns null
  11. repeat function repeat(10) { println("Welcome!") } repeats an action for

    a given number of times
  12. They all are declared as inline functions inline fun <R>

    run(block: () -> R): R = block() inline fun <T, R> T.let(block: (T) -> R): R = block(this) inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null inline fun repeat(times: Int, action: (Int) -> Unit)
  13. inline

  14. inline function compiler substitutes a body of the function instead

    of calling it
  15. inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if

    (!predicate(this)) this else null fun foo(number: Int) { val result = number.takeUnless { it > 10 } ... } Generated code (in the bytecode): fun foo(number: Int) { val result = if (!(number > 10)) number else null ... } inlined code of lambda body
  16. inline fun <T> synchronized(lock: Lock, action: () -> T): T

    { lock.lock() try { return action() } finally { lock.unlock() } } fun foo(lock: Lock) { synchronized(lock) { println("Action") } } fun foo(lock: Lock) { lock.lock() try { println("Action") } finally { lock.unlock() } } Generated code (in the bytecode): inlined code of lambda body
  17. No performance overhead when you use run, let, takeIf, takeUnless,

    repeat No anonymous class for lambda
  18. Reified generics

  19. Reified generics startActivity<NewActivity>("ANSWER" to 42) val anys: List<Any> = listOf(1,

    "one", 2.0) val strings: List<String> = anys.filterIsInstance<String>() ["one"]
  20. Inlining lambda body val anys: List<Any> = listOf(1, "one", 2.0)

    val strings: List<String> = anys.filterIsInstance<String>() inline fun <reified T> List<*>.filterIsInstance(): List<T> { val destination = mutableListOf<T>() for (element in this) { if (element is T) { destination.add(element) } } return destination } inline reified ["one"]
  21. Inlining class reference val intent = Intent(this, NewActivity::class.java)
 intent.putExtra(params)
 startActivity(intent)

    startActivity<NewActivity>("ANSWER" to 42) inline fun <reified T: Activity> Context.startActivity( vararg params: Pair<String, Any>) {
 val intent = Intent(this, T::class.java)
 intent.putExtra(params)
 startActivity(intent)
 } Generated code:
  22. Collections vs Sequences

  23. Extensions on collections are inlined inline fun <T> Iterable<T>.filter(predicate: (T)

    -> Boolean): List<T> inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> inline fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean inline fun <T> Iterable<T>.find(predicate: (T) -> Boolean): T? inline fun <T, K> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>> ...
  24. Collections vs Sequences eager vs lazy evaluation

  25. Sequence interface Sequence<out T> { operator fun iterator(): Iterator<T> }

    val sequence = listOf(1, 2, 3).asSequence() for (i in sequence) { … } val numbers = generateSequence(0) { it + 1 } numbers.take(5).toList() [0, 1, 2, 3, 4]
  26. Collections vs Sequences

  27. Nothing happens until terminal operation is called

  28. Order of operations is important

  29. Collections vs Sequences intermediate collections are created on chained calls

    vs lambdas are not inlined
  30. Copyright © 2017 https://github.com/JetBrains/kotlin-workshop