Svetlana Isakova
November 01, 2017
1k

# 6. The Power of Inline [kotlin-workshop]

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

## Svetlana Isakova

November 01, 2017

## Transcript

1. The power of inline

2. Inlining
Useful library functions
Collections vs Sequences
Agenda

3. Under the Hood
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,

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 satisﬁes 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 run(block: () -> R): R = block()
inline fun T.let(block: (T) -> R): R = block(this)
inline fun T.takeIf(predicate: (T) -> Boolean): T? =
if (predicate(this)) this else null
inline fun 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.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 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

when you use
run, let, takeIf, takeUnless, repeat
No anonymous class for lambda

18. Reiﬁed generics

19. Reiﬁed generics
val anys: List = listOf(1, "one", 2.0)
val strings: List =
anys.filterIsInstance() ["one"]

20. Inlining lambda body
val anys: List = listOf(1, "one", 2.0)
val strings: List =
anys.filterIsInstance()
inline fun List<*>.filterIsInstance(): List {
val destination = mutableListOf()
for (element in this) {
if (element is T) {
}
}
return destination
}
inline reified
["one"]

21. Inlining class reference
val intent = Intent(this, NewActivity::class.java)
intent.putExtra(params)
startActivity(intent)
inline fun Context.startActivity(
vararg params: Pair) {
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 Iterable.filter(predicate: (T) -> Boolean): List
inline fun Iterable.map(transform: (T) -> R): List
inline fun Iterable.any(predicate: (T) -> Boolean): Boolean
inline fun Iterable.find(predicate: (T) -> Boolean): T?
inline fun Iterable.groupBy(keySelector: (T) -> K): Map>
...

24. Collections vs Sequences
eager vs lazy
evaluation

25. Sequence
interface Sequence {
operator fun iterator(): Iterator
}
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