User-Defined Literals in Kotlin
Tags: kotlin, android, productivity, learning
Published: 2020-11-22 21:52:50

## Table of Contents
* [Motivation](#motivation)
* [How it works](#how-it-works)
* [Android Use Case](#android-use-case)
* [References](#references)

## 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:
```kotlin
// is that in meters?
// or in miles?
// or even in royal cubit?
val distance = 42

// in km/h ?
// in mph ?
val speed = 88
```

With user defined literal, it is clear and there is no need for a comment anymore. 
```kotlin
val distance = 42.km

val speed = 88.mph
```


## 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. 

```kotlin
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
```

By the way, I recommend to have also a look at [inline classes](https://kotlinlang.org/docs/reference/inline-classes.html) 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. 

```kotlin 
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)
    }
}
```

## References
* [C++ User-Defined Literals](https://en.cppreference.com/w/cpp/language/user_literal)
* [Jetpack Compose](https://developer.android.com/jetpack/compose)
* [Extension Properties](https://kotlinlang.org/docs/reference/extensions.html#extension-properties)
* [Inline Classes](https://kotlinlang.org/docs/reference/inline-classes.html)
* Cover Image by [arielrobin](https://pixabay.com/users/arielrobin-2483349/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1509707) from [Pixabay](https://pixabay.com/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1509707)