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

Svetlana Isakova

November 01, 2017
Tweet

More Decks by Svetlana Isakova

Other Decks in Programming

Transcript

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

    } runs the block of code (lambda) and returns the last expression as the result
  2. 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
  3. 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
  4. 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
  5. 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)
  6. 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
  7. 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
  8. Reified generics startActivity<NewActivity>("ANSWER" to 42) val anys: List<Any> = listOf(1,

    "one", 2.0) val strings: List<String> = anys.filterIsInstance<String>() ["one"]
  9. 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"]
  10. 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:
  11. 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>> ...
  12. 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]