Kotlin 1.6.0이 나온 이 시점,, 별안간 Kotlin 1.5.0 정리해버리기!
Kotlin 1.5.0에 Value class가 발표되었다! 이는 Inline class로 익숙한 Kotlin language feature이다. 이에 대해 자세히 알아보겠당.
fun checkPassword(password: String)
이런 함수가 있다고 하자. 가독성을 위해 password: String
을 wrapper class를 만들어 사용한다.
// define
class Password(val s: String)
fun checkPassword(password: Password)
// use
checkPassword(Password("..."))
이렇게 사용하면 가독성이 확실히 좋아지지만 성능은?? 런타임 오버헤드가 발생한다. 호출 시 새로운 객체가 만들어져 힙 영역에 할당되기 때문이다. 특히 primitive type은 런타임에 최적화가 되어 있기 때문에 wrapped된 값이 primitive type이면 더욱 성능 영향이 크다고 한다.
JVM에 의해 소스코드가 바이트코드(.class)로 변환될 때 객체로 처리하지 않고 property로 처리하는 클래스를 제공하자.
객체를 생성해 발생하는 비용을 객체로 생성하지 않아 최적화 하는 것이다.
value
modifier를 사용해 선언하고 @JvmInline
annotation을 추가한다.
@JvmInline
value class Password(val s: String)
새로운 타입을 제공하고 런타임에 기존 타입으로 표현되는 것이 type alias와 동일하다. 둘의 차이는 무엇일까?
type alias는 말 그대로 기존 타입의 별칭(assignment-compatible)으로 이미 존재하는 타입의 대체가능한 이름이다. 하지만 inline class는 정말 새 타입이다.
typealias NameTypeAlias = String
@JvmInline
value class NameInlineClass(val s: String)
fun acceptString(s: String) {}
fun acceptNameTypeAlias(n: NameTypeAlias) {}
fun acceptNameInlineClass(p: NameInlineClass) {}
fun main() {
val nameAlias: NameTypeAlias = ""
val nameInlineClass: NameInlineClass = NameInlineClass("")
val string: String = ""
acceptString(nameAlias) // OK: pass alias instead of underlying type
acceptString(nameInlineClass) // Not OK: can't pass inline class instead of underlying type
// And vice versa:
acceptNameTypeAlias(string) // OK: pass underlying type instead of alias
acceptNameInlineClass(string) // Not OK: can't pass underlying type instead of inline class
}