이번 포스팅에선 inline을 왜 사용하는지, 어떻게 사용하는지 알아보려고 한다.
이번 포스팅에서 전부 설명하겠지만, 이전 포스팅에 Kotlin 공식 문서에 있는 inline function, class, property 소개 글을 번역해 놓은 것이 있으니 한 번 보는 것도 좋다.
inline이란?
"Inline"이라는 용어는 프로그래밍에서 사용되는 개념으로, 주로 함수나 코드 블록을 호출하는 위치에 해당 함수 또는 코드 블록의 본문이 복사되어 실행되는 것을 의미합니다. 이렇게 하면 함수 호출의 오버헤드를 줄이고 성능을 향상시킬 수 있습니다.
일반적으로 함수를 호출하면 현재 실행 플로우는 호출된 함수로 이동하고, 해당 함수의 작업이 완료된 후에 호출한 곳으로 돌아옵니다. 이 과정에서 함수 호출의 추가적인 오버헤드가 발생할 수 있습니다.
inline 종류
왜 Inline을 사용하는지 알아보기 전에 어디에 inline을 사용하는지 알아보자.
inline은
- function
- class
- property
위 3 곳에 사용 가능하다.
각 위치 별로 왜 inline을 써야 하는지 알아보자.
inline function
- 어디에 사용할까?
inline function은 고차 함수(high-order functions)에 사용한다.
- 왜 고차 함수에 사용할까?
Kotlin 고차 함수는 성능상 2가지 문제가 있어 inline을 적용하면 성능상 이점을 얻을 수 있기 때문이다.
- Kotlin 고차 함수는 어떤 문제를 가지고 있을까?
exForEach라는 고차 함수를 사용하는 testInline 함수를 예를 들어 설명해보겠다.
아래 코드가 실제 어떻게 돌아가는지 보기 위해 자바 코드로 바꿔보겠다.
fun testInline() {
val commonText = "common"
listOf(1, 2, 3).exForEach { println(commonText) }
}
fun <T> Iterable<T>.exForEach(action: (T) -> Unit) {
for (element in this) action(element)
}
자바 코드로 바꿔보면 아래와 같은데 문제점을 하나씩 설명해보겠다.
① 불필요한 함수 객체 생성
위 부분을 보면 Kotlin의 고차 함수에 사용한 람다가 Function1이라는 클래스로 변환된다. 라는 사실을 알 수 있다.
고차함수를 사용할 때마다 Function1 객체가 생성되기 때문에 성능상 문제가 생길 수 있다.
② 불필요한 변수 캡처링
람다 밖에 있는 변수를 람다 안에서 사용하면 Function1 클래스 내에서 별도 변수를 만들어 할당한다는 사실을 알 수 있다.
불필요한 변수 할당을 하기 때문에 성능상 문제가 생길 수 있다.
- 위 문제점을 inline으로 해결해보자.
exForEach 함수에 inline을 붙여주자. 그럼 끝이다.
자바 코드로 변환해보면 아래와 같다.
inline을 붙이니 exForEach를 호출하지 않고 exForEach에 있는 코드를 testInline에 아예 옮겨버렸다.
위에 문제점 ① 불필요한 함수 객체 생성, ② 불필요한 변수 캡처링이 사라진 걸 볼 수 있다.
- 모든 고차 함수에 적용해도 될까?
엄청 긴 고차 함수를 inline하면 코드 수가 증가해서 컴파일 속도가 늦어진다고는 한다.
그래서 어디는 3줄 어디는 5줄 이내로 작성된 것들만 사용하라고 하는데 정확하게 잘 모르겠다.
일단 적용해보고 정말 느리면 그때 빼도 될 거 같다는 생각이 든다.
inline class
- 어디에 사용할까?
value class에 사용한다.
- 왜 value class에 사용할까?
value class에 있는 value 타입으로 컴파일되게 하기 위해서 사용한다.
- inline이 어떻게 작동하는지 확인해보자.
inline class는 class 앞에 inline을 붙이지 않고 @JvmInline 어노테이션을 붙여야 한다.
value class는 inline이 필수다. 없으면 에러가 발생한다.
Money value 클래스를 예로 들어 설명하겠다.
예:
아래 Money 클래스를 사용하는 Payment 클래스를 자바 코드로 변경해보겠다.
data class Payment(
val money: Money
)
@JvmInline
value class Money(val money: Long)
Money 클래스가 long 타입으로 변경된 걸 볼 수 있다.
이걸 위해 @JvmInline을 붙이는 거다.
inline property
- 어디에 사용할까?
custom property에 사용한다.
- 어떻게 사용할까?
var foo: String
inline get() = Foo()
inline set(v) { ... }
getter, setter에 각각 inline을 붙일 수 있다.
inline var foo: String
get() = Foo()
getter, setter 둘 다에 적용시키고 싶다면 val, var 앞에 inline을 붙여주면 된다.
주의할 점은 백킹 필드를 쓸 수 없다.
- 왜 custom property에 사용할까?
아래와 같이 생긴 property를 사용하면 런타임에 어떻게 되는지 자바 코드로 변경해보겠다.
val String.lengthInUpperCase: Int
get() = this.uppercase().length
fun main() {
"노력남자".lengthInUpperCase
}
getLengthInUpperCase() -> this.uppercase().length 2번 호출하는 걸 볼 수 있다.
이걸 this.uppercase().length 1번만 호출하게 변경하면 얼마나 좋을까?
- inline을 붙여보자.
inline val String.lengthInUpperCase: Int
get() = this.uppercase().length
fun main() {
"노력남자".lengthInUpperCase
}
inline을 붙여주니 String.lengthInUpperCase를 호출하지 않고 바로 this.uppercase().length를 호출하는 걸 볼 수 있다.
'Kotlin' 카테고리의 다른 글
[Kotlin] inline 사용법 (3) - noinline 사용법 (0) | 2023.08.15 |
---|---|
[Kotlin] inline 사용법 (2) - reified 사용법 (0) | 2023.08.15 |
[Kotlin] Kotlin 공식 문서 번역 - 인라인 value 클래스 (Inline value classes) (0) | 2023.08.12 |
[Kotlin] Kotlin 공식 문서 번역 - 인라인 함수 (Inline functions) (0) | 2023.08.12 |
[Kotlin] Kotlin 공식 문서 번역 - 고차 함수와 람다 (High-order functions and lambdas) (0) | 2023.08.12 |
댓글