Blog Infos
Author
Published
Topics
Published
Topics

Often, when working with a single value used commonly across your project, you’ll want to wrap it in a class to encapsulate its logic and avoid making multiple Util classes for it.

Here’s an example of such a class for Name that is a String , but we’ll often want to format it in different ways.

class Name(
    private val name: String,
) {
    fun hello() = "Hello $name"

    ...
}
1. The Problem

However, we sacrifice efficiency for readability because the program needs to allocate a new class.

It can become severe and slow your app when:

  • We need to create many objects. We’re introducing a lot of overhead in runtime due to allocations.
  • We’re working with primitive types. Primitive types are heavily optimised in runtime, and we lose all of those optimisations by wrapping them.
2. The Solution

By using Kotlin, value class we avoid allocations. In runtime, no additional classes are going to be created. Here’s how you need to modify the class:

// Required when working with Kotlin in JVM
@JvmInline
value class Name(
    private val name: String,
) {
    fun hello() = "Hello $name"

    ...
}

No instantiation of a Name class happens. Instead, the class is represented by a single property, in this case a String .

fun main() {
    // No instantiation of a class Name happens
    // It's represented by a String
    val userName = Name("Michael")
}

Now that we know all of this, what are the limitations of such classes? Frankly speaking, the biggest limitation is that they only work when we have single property classes. Apart from that, they can be used like normal classes:

3. Functions, init and constructors

Here’s an example of what we can do with the Name class:

@JvmInline
value class Name(
    private val name: String,
) {
    init {
        if (name.isBlank()) throw IllegalArgumentException()
    }

    constructor(firstName: String, secondName: String) : this("$firstName $secondName")

    fun hello() = "Hello $name"
}

As you can see, you can do everything a normal class would do and get the performance benefits if it has a single field. We’re even able to use…

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

No results found.

Jobs

4. Inheritance

It’s not uncommon for these types of classes to have to implement some type of interface which inline class supports. For example, we could make our Name class implement Greetable interface.

interface Greetable {
    fun greet(): String
}

value class Name(
    private val name: String,
): Greetable {
    override fun greet(): String = "Greetings $name"
}
5. Boxing and unboxing

To be able to use inline class like a normal class Kotlin compiler will keep a wrapper for each of the inline class . It works similarly to the Int , which in Kotlin can be treated as a primitive and a wrapper.

Using a wrapper is called boxing, while using underlying types is called unboxing. In short, Kotlin will box the inline class whenever it’s used as another type. Here are a couple of examples:

fun useInlined(name: Name) {}
fun useNullable(name: Name?) {}
fun useInterface(greetable: Greetable) {}
fun <T> useGeneric(t: T) {}

fun main() {
    val name = Name("Michael")

    useInlined(name)   // Unboxed: compiler will use a String
    useNullable(name)  // Boxed
    useInterface(name) // Boxed
    useGeneric(name)   // Boxed
}

If you’ve found this article helpful, please clap so it’s easier for others to see it, and follow me for more!

Based on:

https://kotlinlang.org/docs/inline-classes.html?source=post_page—–090fe64829e6——————————–#members

This is previously published on proandroiddev.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
In this part of our series on introducing Jetpack Compose into an existing project,…
READ MORE
blog
This is the second article in an article series that will discuss the dependency…
READ MORE
blog
Let’s suppose that for some reason we are interested in doing some tests with…
READ MORE
Menu