DEV Community

Cover image for User-Defined Literals in Kotlin
Arooran Thanabalasingam
Arooran Thanabalasingam

Posted on

User-Defined Literals in Kotlin

Table of Contents

Motivation

In general a code is written by one person. Later the same code is maintained by another person. Since we all grew up in different places, we have different views of what the standard unit is. As shown below, the lack of dimensions makes maintaining a code base harder:

// is that in meters?
// or in miles?
// or even in royal cubit?
val distance = 42

// in km/h ?
// in mph ?
val speed = 88
Enter fullscreen mode Exit fullscreen mode

With user defined literal, it is clear and there is no need for a comment anymore.

val distance = 42.km

val speed = 88.mph
Enter fullscreen mode Exit fullscreen mode

How it works

I learned about user-defined literals for the first time in the language C++. Thanks to the Extension Property in Kotlin, we can also create custom literals.

data class Distance(val distanceInKm: Double){
    companion object {
        const val MI_TO_KM = 1.609344

        fun createFromMiles(distance: Double): Distance {
            return Distance(MI_TO_KM * distance)
        }
    }
}

// our extensions properties
val Int.km: Distance
    get() = Distance(this.toDouble())

val Int.mi: Distance
    get() = Distance.createFromMiles(this.toDouble())


// et voilà
val foo: Distance = 42.km
val bar: Distance = 26.mi
Enter fullscreen mode Exit fullscreen mode

By the way, I recommend to have also a look at inline classes even if it is in alpha state. It is very similar to Scala's value classes.

Android Use Case

I recently wanted to change padding in button view. There I was inspired how Jetpack Compose has solved it.

interface ViewHelper {
    val ctx: Context

    val Int.dp: Int
        get() = 
            TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                this.toFloat(),
                ctx.resources.displayMetrics
            ).toInt()

    val Int.sp: Float
        get() = 
            TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP,     
                this.toFloat(),
                ctx.resources.displayMetrics
            )
}


class MainActivity : AppCompatActivity(), ViewHelper {
    override val ctx = this

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // ...

        button.setPadding(8.dp, 8.dp, 8.dp, 8.dp)
    }
}
Enter fullscreen mode Exit fullscreen mode

References

Top comments (0)