Hanbit the Developer

Kotlin Documentation | Inline classes 본문

Mobile/Kotlin

Kotlin Documentation | Inline classes

hanbikan 2023. 5. 23. 15:38

Kotlin Documentation 시리즈에 대해

Category: Concepts - Classes and objects

문서 링크: https://kotlinlang.org/docs/inline-classes.html


Backgrounds

class Password(private val s: String)
  • 위처럼 데이터가 한 개가 필요하지만 클래스로 wrap해야 하는 경우가 있다.
  • 위처럼 하면 힙에 인스턴스를 추가해야 하기 때문에 오버헤드가 심하다.(primitive type일 경우에는 특히 더 심하다.)

Usage

value class Password(private val s: String)
// To declare an inline class for the JVM backend
@JvmInline
value class Password(private val s: String)

 

Attributes

  • single property
  • immutable(val property만 가능)
  • Inheritance, delegation(by) 가능

vs data class

automatically generates:

data class equals(), toString(), hashCode(), copy(), componentN()
inline class equals(), toString(), hashCode()

Members

@JvmInline
value class Name(val s: String) {
    init {
        require(s.length > 0) { }
    }

    val length: Int
        get() = s.length

    fun greet() {
        println("Hello, $s")
    }
}

fun main() {
    val name = Name("Kotlin")
    name.greet() // method `greet` is called as a static method
    println(name.length) // property getter is called as a static method
}

Representation

interface I

@JvmInline
value class Foo(val i: Int) : I

fun asInline(f: Foo) {}
fun <T> asGeneric(x: T) {}
fun asInterface(i: I) {}
fun asNullable(i: Foo?) {}

fun <T> id(x: T): T = x

fun main() {
    val f = Foo(42)

    asInline(f)    // unboxed: used as Foo itself
    asGeneric(f)   // boxed: used as generic type T
    asInterface(f) // boxed: used as type I
    asNullable(f)  // boxed: used as Foo?, which is different from Foo

    // below, 'f' first is boxed (while being passed to 'id') and then unboxed (when returned from 'id')
    // In the end, 'c' contains unboxed representation (just '42'), as 'f'
    val c = id(f)
}

vs typealias

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
}

References

https://velog.io/@dhwlddjgmanf/Kotlin-1.5에-추가된-value-class에-대해-알아보자