본문

171215(금) - Kotlin docs (Inline Functions)

Kotlin docs 


Inline Functions


- higher-order functions를 사용하면 runtime penalties가 부여된다.

- each function은 object이며 function의 body에서 accessed되는 variables인 closer를 캡쳐한다. (?)

- memory allocations (both function objects and classes) and virtual calls는 runtime overhead를 초래한다.

- 이러한 많은 종류의 overhead case들은 inlining the lambda expressions를 사용함으로써 eliminated 된다.

- lock() function은 call-sites에서 쉽게 inline 될 수 있다.

lock(l) { foo() }

- parameter에 대한 function object를 만들고 generating call을 하는 대신 compiler에서 아래 코드를 생성 가능하다.

l.lock()
try {
    foo()
}
finally {
    l.unlock()
}

- compiler가 위와같이 만들게 하려면 inline modifier를 mark해야한다.

inline fun <T> lock(lock: Lock, body: () -> T): T {
    // ...
}

- inline modifier는 function itself와 전달된 lambdas에 영향을 미치고 모두 call site로 inlined된다.

- inline하면 code가 더 커질 수 있다. 하지만 reasonable way로 loop를 수행하면 performance가 좋을 것이다.

- 특히 loop내부의 megamorphic call-sites에서 효과가 좋다.



noinline

- inline functions에 전달된 일부 lambdas만 inline되도록 하려면 noinline modifier를 사용해서 function parameters중 일부를 표시할 수 있다.

inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
    // ...
}

- inlinable lambdas는 inline functions 내에서만 call 되거나 inlinable arguments로 전달 될 수 있다.

- 하지만 noinline은 stored in fields, passed arounds 등 어떤 방식으로든 사용가능

- inline function에 inlinable functions and reified type parameters가 없으면, compiler에서 해당 functions를 inline하게되면 매우 유용하지 않으므로 compiler는 warning을 표시한다. (@Suppress("NOTHING_TO_INLINE")사용으로 warning 해제 가능) 



Non-local returns

- kotlin에서는 non named function or anonymous function을 exit하기 위해 unqualified return만 사용할 수 있다.

- lambda를 exit하려면 label을 사용해야 하고 lambda안에서 bare return을 금지한다.

fun foo() {
    ordinaryFunction {
        return // ERROR: can not make `foo` return here
    }
}

- 그러나 lambda 전달된 function가 inline이라면 return도 inline 될 수 있으므로 사용 가능하다.

fun foo() {
    inlineFunction {
        return // OK: the lambda is inlined
    }
}

- 이러한 return을 non-local returns라고 부른다.

fun hasZeros(ints: List<Int>): Boolean {
    ints.forEach {
        if (it == 0) return true // returns from hasZeros
    }
    return false
}

- 일부 inline functions는 parameter로 전달된  lambdas를 function body에서 직접 call 하지 않고 local object나 nested function 같은 다른 context에서 호출 가능하다. 

- 이런 경우 lambdas에서도 non-local control flow는 허용되지 않는다.

- 이를 나타내기 위해 lambda parameter에 crossinline modifier가 필요

inline fun f(crossinline body: () -> Unit) {
    val f = object: Runnable {
        override fun run() = body()
    }
    // ...
}


- break와 continue는 아직 inline lambdas에서 사용 불가능하지만 support할 계획이 있다.



Reified type parameters































공유

댓글