GeistHaus
log in · sign up

OkKotlin

Part of OkKotlin

A premier blog on Kotlin.

stories primary
Safely accessing lateinit variables
Kotlin, by design, doesn't allow a non-null variable to be left uninitialised during its declaration. To get past this issue, Kotlin's…
Show full content

Kotlin, by design, doesn't allow a non-null variable to be left uninitialised during its declaration.

To get past this issue, Kotlin's lateinit allows us to declare a variable first and then initialise it some point in the future during our program's execution cycle.

The concept is simple, but when we try to access an uninitialised property, it's a different story. Let's talk more about that.

First, let's crash our app

Whenever we declare a lateinit var, we need to initialise it before we can access it. Failing to do that will result in an exception as follows:

Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property fullName has not been initialized at UninitializedPropertyKt.main(UninitializedProperty.kt:3)

The above is not one of those warnings that we can safely ignore and move on. An exception like this will crash our app.

And this is a common situation. For example, in an Android app:

We might have a list of news items that we need to fetch from a remote server. When the data finally arrives, we need to initialise a RecyclerView adapter, let's say NewsAdapter based on that data to show up the news articles.

What do you think will happen when we try to access that adapter before we initialise it with the fetched data?

Our app crashes because of the exception we talked about earlier. The lateinit var adapter: NewsAdapter has not been initialised.

Does that mean lateinit properties are useless? No.

Here's a secret:

Before accessing the property, we can check if it's initialised or not.

There's a reflection based API

On Kotlin 1.2 and up, we can quickly check whether a lateinit property has been initialised or not using a reflection based API.

Here's how it works:

lateinit var fullName: String
    
if (::fullName.isInitialized) {
    print("Hi, $fullName")
}

You can read more about this API in the official blog post announcing this update.

The backing field might not be accessible always

There's a small caveat here. This reflection API works only on properties which are defined:

  • In the same class where the check is being made
  • In an outer class
  • As top-level in the same file

So, if we have a lateinit property in one class and try to check whether it's initialised or not in another class, like this:

class LateComer {
    lateinit var student: Student
}
    
class School {
    val lateComer = LateComer()
    
    fun printLateComer() {
        if (lateComer::student.isInitialized) {
            println("Late Comer: ${lateComer.student}")
        }
    }
}

The program will get a compile time error saying:

Error:(9, 32) Kotlin: Backing field of 'var student: Student /* = String */' is not accessible at this point

In some case, where we need to verify whether lateinit property of some class is initialised or not, there's a workaround.

Taking note from this StackOverflow answer, we can check lateinit properties of other classes by adding a new method on the target class:

class LateComer {
    lateinit var student: Student
    
    fun isStudentInitialised() = ::student.isInitialized
}

It is not an elegant solution but it works.

Safe to use

This API is neither experimental nor unstable. I have been using it for a long time, and it works every time.

Feel free to take advantage of this small feature and instead of ditching lateinit altogether and falling back to nullable properties.

Here's a sketch note on the topic

Lateinits sketch note

https://okkotlin.com/lateinits/
Uniform list access with subscripts
Accessing values from an array using subscripts is a light and easy way to fetch list data. Kotlin brought uniformity in data access across…
Show full content

Accessing values from an array using subscripts is a light and easy way to fetch list data.

Kotlin brought uniformity in data access across regular arrays and Lists by allowing us to access data from a List using subscripts.

But, what about our custom data models? Can they have subscripts if they mostly represent a list of data?

This week, we will be discussing how we can add subscript access to our custom data models through operator overloading.

Subscripts are handy

Subscripts or the [] make it possible to have an incredibly lightweight and consistent syntax for accessing elements in an array.

It's like moving a small window over a list of items to pick one.

Subscripts access strategy

In Java, subscripts are not available for data structures such as List. To access an element from the List we have to call the get(index: Int) method.

In Kotlin, however, we can access List elements the same way we access an array.

val names: List<String> = listOf(
    “James Arthur”,
    “Brett Eldredge”
)

println(“Artist: ${names[0]}”)

This improved syntax is handy because we don’t have to remember different method names or access strategies for different data structures.

No matter if we have an array or a List, as long as our naming convention represents the property to be a sequence of data, we can apply the same access method.

Our code becomes robust in the sense that we can easily swap out arrays with Lists and our code will work.

Now the question is, can we build subscript access for our custom data models?

Yes, we can. Before we get into the implementation, let’s see how subscripts work for Lists in Kotlin.

It’s a case of operator overloading

Kotlin supports operator overloading with the keyword operator. While there are plenty of standard operator overloads available, we will focus on getting the [] access working for our custom class in this article.

A quick look into the List<E> class of kotlin.collections shows up an overloaded get(index: Int) like this:

public operator fun get(index: Int): E

The standard behaviour is that Kotlin transforms get(index: Int) methods marked with the operator keyword to [] during access.

With this little syntactic sugar, we can access List and ArrayList items with the subscript notation.

Let’s make a mixtape

To understand how and where we can leverage subscripts, we are going to work through an everyday use case, mixtapes.

Popular music apps these days provide personalised lists of tracks for us to listen every day. Some, like YouTube music, call these playlists as mixtapes.

Building on this idea, we can have our custom data model called Mixtape like this:

data class Mixtape(
    val title: String,
    val forUser: String,
    val tracks: List<Track>
)

operator fun Mixtape.get(index: Int): Track = tracks[index]

val Mixtape.size
    get(): Int = tracks.size

Here, we have defined a get(index: Int) method marked as an operator to enable subscript access for our class.

For brevity, our Mixtape here simply returns elements from the tracks list. However, we can have logic inside this get() method to suit our needs. An example would be returning sorted or filtered tracks.

We have also defined a size property to add list-like functionality to our Mixtape class, so that we can use it like this:

for (index in 0 until mixtape.size) {
    val track = mixtape[index]
    println(“${track.title} - ${track.artist}”)
}

Wondering why we have used extension functions and properties for our Mixtape instead of having them defined inside the class?

It’s because, with this approach, we can have clean models with logic separated from the data, as we discussed in the clean models article.

How is this helpful?

At a glance, this little technique might not seem to be of much value. However, semantically it’s a win.

Data classes like Mixtape and Podcasts indicate they are a list of items. Having a uniform data access strategy for lists in our project helps us skip the appropriate method lookup.

For example, whenever we get a Mixtape object, we know it’s a list of songs, and we can traverse it like an array. We don’t have to dig into the implementation of Mixtape to find out how to extract elements from it.

This semantic structuring not only saves us time but also prevents us from writing code like this:

for (index in 0 until mixtape.tracks.size) {
    val track = mixtape.tracks[index]
    println(“${track.title} - ${track.artist}”)
}

We can go a step further to hide our List<Track> from external access if we have some business logic inside our Mixtapes get() method:

data class Mixtape(
    val title: String,
    val forUser: String,
    private val tracks: List<Track>
) {
    operator fun get(index: Int): Track = tracks[index]

    val size
        get(): Int = tracks.size
}

With this encapsulation, we can ensure that our Mixtape always returns the output we intend it to, like a sorted or filtered list of tracks. Careful access means fewer bugs.

A quick note:

If we resort to locking down our class members to private visibility, we cannot access the private members inside an extension function/property defined outside the class.

Therefore, we need to move get(index: Int) and size inside the Mixtape class block.

Small but incremental wins

As always, improvements like subscripts aren’t going to make our code faster or increase our productivity tenfold.

These are small improvements, like type aliases or inline classes which compound to a clean and well-maintained project.

Choose how you use them.

Here's a sketch note on the topic

Subscripts sketch note

https://okkotlin.com/subscripts/
Computed properties with property getters
Custom getters and setters for fields in a class is not a new idea. We have been using them since our early days in programming. Kotlin…
Show full content

Custom getters and setters for fields in a class is not a new idea. We have been using them since our early days in programming.

Kotlin, however, takes that concept to a more elegant level by allowing us to define getters and setters at the declaration site of our properties.

The primary advantage of this feature is the immediate connection we can make between a declared property and the logic that transforms the property.

This week, we will be discussing how we can make our code more meaningful and easy to decipher using property getters and setters, a.k.a. computed properties.

Computed properties make beautiful code

Like type aliases, the best value in using computed properties is to have a slick and readable codebase.

There's nothing extra that we can do with a computed property that we cannot do with a plain old method. We can define our own getter and setter methods to make fields return a computed value.

The problem with having logic inside our getter methods is that if we mistakenly access the field value instead of its getter, we are skipping our business logic. This approach will result in miscalculations or a lousy output.

Having logic inside Kotlin's property getters ensure that there is only one way to access a property, and it will return the correct value every time.

Here's an example:

var formattedSpeed: String
    get(): { return "$field km/h" }

Now, every time we access formattedSpeed, we will get a formatted speed value indicating the unit. We don't have to do a string interpolation ourself every time we set a speed value.

formattedSpeed = "55"
println("Speed is $formattedSpeed")
    
// Output: Speed is 55 km/h

This example above might seem like a lame one, but it's just a starting point to get creative.

We can also create virtual properties

Virtual properties aren't actual fields that you have in a class but are merely wrappers on top of some other property.

The following example will clear things up:

Suppose we have to build a content management system which lets our users manage multiple publications from a single dashboard. If we want to have a section where we show up all posts across publications, we need to run a loop like the following one everywhere we want the posts to show up:

val allPosts = mutableListOf<Post>()
    
publications.forEach {
    allPosts.addAll(it.posts)
}

To make this logic reusable, we can wrap it inside a function:

fun getAllPosts(): List<Post> {
    val allPosts = mutableListOf<Post>()
    
    publications.forEach {
        allPosts.addAll(it.posts)
    }
    
    return allPosts
}

Now, here's a trick. For simple cases like the aggregation shown above, it's way better to declare a computed property like this:

val allPosts: List<Post>
    get() {
        val aggregate = mutableListOf<Post>()
    
        publications.forEach {
            aggregate.addAll(it.posts)
        }
    
        return aggregate
    }

This change makes accessing all posts from across publication a simple reference to our new virtual property called allPosts.

allPosts.forEach {
    println(it.title)
}
    
// Output: Prints out all blog posts titles

The reason I'm calling this a virtual property is because this property is not an actual field defined in the class. It's just a wrapper which returns a value calculated from other properties in the class.

Also, if we look closely, there's nothing new that we did with a computed property that we couldn't have done with the function getAllPosts(). Defining the property just made our code much more elegant and predictable.

Handle computed properties with care

The allPosts computed property we just created, can be a hidden mess, if not treated carefully. From a 35,000 ft view all seems reasonable, but if we look closely, each property access is of the time complexity O(N2).

A little knowledge of algorithms is enough to tell that this is bad. Sure, computing has evolved, and it's getting faster than ever. However, in some instances, this code can lag our super fast smartphone to an extent where it's noticeable.

Take Android's RecyclerView as an example. When a RecyclerView populates a list of data on the screen, it repeatedly calls the bindViewHolder() method as the user scrolls through the list.

List of items

A heavy operation such as accessing a computed property which takes O(N2) time inside bindViewHolder() can easily cause visible jank while scrolling through a list.

This broken experience can go unnoticed when our data set is small, let's say our list contains only ten items. But, let's face it; real-world apps deal with way more data than that. One hidden bug can lead to painful debugging time.

If we want or need to use a computed property in these cases, we can either:

  • Make sure the computation logic is fast, or
  • Compute once and pass the result during our class's initialisation

In the previous case, instead of accessing the computed property on every bindViewHolder() call, we can pass a previously computed value to the adapter's constructor, like this:

class PostsListAdapter(private val allPosts: List<Post>)

The computation logic inside the allPosts is run only once when we initialise our PostsListAdapter, no matter how many times the bindViewHolder() method is called.

Making them reactive

Using computed properties in Vue.js, I was pretty accustomed to the fact that computed properties were de-facto reactive.

Reactive means that if a computed property depends on some other property, when that property changes, the computed property gets recalculated. This behaviour usually triggers a view change with the updated result.

In Kotlin, sadly, that's not the case.

Recalculation will only be done once the property value is set or accessed depending on where we have written our calculation logic.

We can achieve a reactive behaviour by using Kotlin's property observer delegate, though. It's a patch but let's see how it can be done.

We need a backing property which we will keep updating and route the output through our computed property.

Let's say we need to display a formatted speed value to the user whenever the speed gets updated. Here's how we can sprinkle in some reactivity:

private var _formattedSpeed: String by Delegates.observable("0") { _, _, _ ->    
    displaySpeed(formattedSpeed)
}
    
val formattedSpeed: String    
    get() = "$_formattedSpeed km/h"

Here, we are observing a private counterpart of our computed property, which we call the "backing property". Whenever our backing property changes, we display the change to the user.

A little detail here is, on every change of the backing property value, we are querying the value of the computed property and passing it down to our displaySpeed() method.

This approach ensures that the updated value goes through the computed property, and necessary transformations are applied before it reaches the user.

You'll rarely need to rely on this technique. However, it could be handy to be aware of this possibility.

Uh-oh! The stack is full

Stacks are nice, but no one wants to overflow their stacks.

Similar to recursion, it's pretty easy to get hit on the face with a StackOverflowException if we don't write our computation logic well.

In Kotlin, any property we define is not a direct reference to a memory address. This means that every time we access value from a property, it comes through the get() method.

A code like this is a sure-shot way to get a StackOverflowException:

val formattedSpeed: String    
    get() = "$formattedSpeed km/h"

Every time we access formattedSpeed, we call it's get() method. Also, in the get() method we are trying to access formattedSpeed, which in turn calls the get() method again. This process continues until the device's stack can't hold any more method calls.

Thus, the dreaded StackOverflowException.

If we need to access the computed property's actual value, we need to access its backing field instead of the property.

The above code becomes:

var formattedSpeed: String = ""
    get() = "$field km/h"

Here, field is the keyword used to access the actual value of a property. Think of it as a direct reference to the memory.

It's essential to be aware of this common mistake to avoid losing time in debugging.

Making the most out of it

Just because computed properties exist, doesn't mean we should never write a simple property again. Language features such as this are most useful when there's a particular use case for them. Like the ones, we discussed above.

Look at your code, be creative and think if using computed properties somewhere makes your code better. If not, well, stick to the plain old val goodByeMessage = "Sayonara!" .

Here's a sketch note on the topic

Computed properties sketch note

https://okkotlin.com/computed-properties/
Low-overhead wrappers using inline classes
Previously, we discussed how Kotlin's type aliases could make our code more readable. However, if you remember, since type aliases don't…
Show full content

Previously, we discussed how Kotlin's type aliases could make our code more readable. However, if you remember, since type aliases don't introduce new types, they don't provide any type-safety.

This week we will be exploring Kotlin's experimental inline classes which have benefits that type aliases provide but go further than that.

A little about inline classes

Kotlin introduced inline classes in their 1.3 release, advertised as light-weight wrapper classes. What separates inline classes from traditional wrappers is that inline classes don't add any overhead due to no additional heap allocations.

Now that's a mouthful. Let's see what that means. Consider this function:

fun renderLocation(latitude: Double, longitude: Double) {
    map.render(latitude, longitude)
}

Since both latitude and longitude are Double values, it's easy to pass them in the wrong order making our program render an incorrect map.

We can prevent this error by introducing two wrapper classes called Latitude and Longitude like this, thereby, making our function type-safe:

class Latitude(val value: Double)
class Longitude(val value: Double)
    
fun renderLocation(latitude: Latitude, longitude: Longitude) {
    map.render(latitude, longitude)
}

Although we made our function type-safe, we added a little overhead here. Every time we pass new values to our renderLocation function here, we need to initialise two new objects. This approach, as you might have guessed, results in additional expensive heap allocations.

The previous version of our function didn't have this problem because primitive values are optimised by the compiler.

All hope's not lost, yet:

We can convert our plain old wrapper classes into inline classes to prevent any extra initialisation.

How?

Well, the Kotlin compiler treats inline classes as a drop-in replacement for their underlying value. Therefore, if we do this:

inline class Latitude(val value: Double)
inline class Longitude(val value: Double)
    
fun renderLocation(latitude: Latitude, longitude: Longitude) {
    map.render(latitude, longitude)
}

When we run our program, Kotlin will try to replace every usage of Latitude or Longitude with a Double value.

Replacing Latitudes with Doubles

In cases where the type has to be retained, like for a type check using the as keyword, Kotlin will box the Double value into the appropriate wrapper class.

Keep in mind that type erasure happens only during runtime or when your Kotlin code gets compiled to byte code. In our source code, we get full type support that we don't get while using a type alias.

A decompiled Java version of our renderLocation will be this:

public static final void renderLocation_vKZqJUM/* $FF was: renderLocation-vKZqJUM*/(double latitude, double longitude) {
    map.render-vKZqJUM(latitude, longitude);
}

Notice how the function parameters are plain old primitive double values.

What happened to our function name?

We named our function as renderLocation, but our Java code shows a weird name renderLocation-vKZqJUM, what's the deal here?

It turns out, inline classes only work when we are writing Kotlin code. The hot-swapping of an inline class to its underlying type doesn't happen in Java.

As a result, if we have multiple functions like this:

fun renderLocation(latitude: Double, longitude: Double) {}
    
fun renderLocation(latitude: Latitude, longitude: Longitude) {
    map.render(latitude, longitude)
}

A straightforward conversion to Java code would look like:

public static final void renderLocation(double latitude, double longitude) {}
    
public static final void renderLocation(double latitude, double longitude) {
    map.render(latitude, longitude);
}

The above code is not valid because we can't have two methods with the same signature.

To deal with this collision problem, Kotlin adds a "-hash code" to all methods which have an inline class parameter in their Kotlin counterpart. This technique is called mangling.

Although this trick solves the collision issue, it creates another problem. We can't refer to any of our Kotlin functions which accepts an inline class parameter from our Java code.

Why?

Because, in Java, "-" is considered an illegal symbol. Therefore, it is impossible to call methods which has a "-" in their names.

This is where Kotlin-Java interoperability breaks for us.

Don't let this be a blocker though

Casting aside the interoperability problem, Kotlin's inline classes are quite handy in a variety of cases.

As we saw in our renderLocation function, using inline classes makes our program bug free by enforcing compile-time type-safety. We can't wrongly pass a Latitude value as Longitude to our function here. The compiler won't allow this misplacement.

Jake Wharton pointed out another extensive use case for inline classes in one of his blog post – type-safe database IDs.

Similar to our example here, database IDs are easy to misplace due to being of the same type. We can slip a payment ID as a customer ID and not notice until we get an incorrect result during runtime. Inline classes prevent these errors during compilation.

Comparing with type aliases

Type aliases don't introduce a new type. They mask an existing type to a different name.

Inline classes, however, introduce new types which are available for us to harness while writing our programs.

That doesn't mean type aliases are useless; they are useful for a different reason as we discussed in an earlier article.

A few caveats to keep in mind

Owing to the nature of their design, inline classes, right now:

  • cannot have init blocks in them
  • can neither inherit from another class nor can be open for extension
  • cannot have any property with a backing field

They can, however, have simple computed properties like this:

inline class Longitude(val value: Double) {
    val formattedValue: String
        get() = "$value°"
}
Enforcing contracts with interfaces

Inline classes can implement interfaces. This feature gives us the ability to enforce some contracts for our wrappers.

Take out Latitude and Longitude wrappers as an example. We can define a contract for all geolocation values to have a formatting method, like this:

interface GeoUnit {
    val formattedValue: String
}

Modifying our inline classes to implement this interface will ensure all implement classes have at least a formattedValue property which returns a String value. Here, we can make use of this property to pretty print our location value:

inline class Latitude(val value: Double) : GeoUnit {
    override val formattedValue: String
        get() = "$value°"
}

We can now have consistent functionalities across wrappers of similar type.

Refactoring already?

Inline classes can be tempting to use. However, if you have an existing codebase, it's better to take a step back and think whether using inline classes would be suitable or not.

Firstly, as of Kotlin 1.3.6, inline classes are still at an experimental stage. Refactoring a large project with experimental API can be detrimental.

Also, if your codebase is mostly in legacy Java code, using inline classes means losing access to a bunch of methods from your Java classes.

Before plunging into a full refactor mode, weigh in pros and cons and then make a decision.

Here's a sketch note on the topic

Inline classes sketch note

https://okkotlin.com/inline-classes/
Writing clean models using extensions
Models in Kotlin with data classes are already leaner and cleaner than their Java counterparts. Abstracting away all those getters, setters…
Show full content

Models in Kotlin with data classes are already leaner and cleaner than their Java counterparts. Abstracting away all those getters, setters, toString() and copy() method with a single keyword makes our models reflect the only thing they should be concerned about — holding data.

As I was exploring Swift for a project, I came across a lovely concept of separating business or transformation logic from models with the help of extensions. This week, we will apply this concept to our Kotlin data classes.

When requirements outgrow a pure data class

A simple data class in our project is the purest form of a model we can have. I mean, look at this:

data class Podcast(    
    val name: String,    
    val description: String,    
    val category: String,    
    val publisher: String,    
    val website: String
)

One quick peek and we know it's a Podcast model and what data we need to provide to get an instance of this class.

The data keyword indicates that we have access to all those fancy methods like, copy() and toString() without any extra line of code.

In reality, however, our model classes might have to do a bit of extra work than just being data containers. Having convenience methods to format data from model class properties is a known practice.

From a bird's eye view, the following class will probably seem fine:

data class Podcast(    
    val name: String,    
    val description: String,    
    val category: String,    
    val publisher: String,    
    val website: String
) {    
        fun getPublisherMeta(): String = "$publisher: $website"    
        fun getQualifiedUrl(): String = "https://$website"
}

After all, there's nothing wrong in having two convenience methods to print out podcast meta data. They are strongly related to the model we are working with.

However, adding utility methods inside our models tank their readability level. Our model is no longer a simple container for data. It has logic mixed up with data.

Throw in a few more methods, and we will no longer have that "one quick peek to know the data" readability.

Should we put logic inside our model classes?

Having logic inside a model class is fine. But imagine:

What if we could have some boundary between the data and logic in our models?

Boundary between logic and data

That would make our models stay true to their name. One separate block of code depicting a pure data entity and nothing more.

// Pure data part
data class Podcast(    
    val name: String,    
    val description: String,    
    val category: String,    
    val publisher: String,    
    val website: String
)

Now, the question that comes is where exactly to put any added functionality if not within the class itself. There's a Kotlin way to this problem.

Added functionalities as extensions

We can use Kotlin's extension functions to cut-paste logic from our data classes to top-level functions.

With this approach, our previously bloated data class breaks down into two separate units:

// Pure data part
data class Podcast(    
    val name: String,    
    val description: String,    
    val category: String,    
    val publisher: String,    
    val website: String
)
    
// Business logic part
fun Podcast.getPublisherMeta(): String = "$publisher: $website"
fun Podcast.getQualifiedUrl(): String = "https://$website"

Even if we add a hundred extension functions, from a readability standpoint, our Podcast model is still lean and a separate block of code. Also, functionality wise, this approach is essentially the same as that we had before.

That means, we can still call getPublisherMeta() on a Podcast instance, and it will return the correct value depending on which instance we are calling the method on.

The only difference is, our model classes read better now.

We can go a step further here and extract out the extension functions in a separate file. However, that kind of separation is often unnecessary.

Your mileage may vary

There's no one way to achieve something. Programming is a significant proof of this concept. Programmers have their particular coding style preferences.

I would suggest you take this approach out for a spin and see if it makes sense for your projects. It's a small refactor with a decent treat for your and your teammates' eyes.

Here's a sketch note on the topic

Clean models sketch note

https://okkotlin.com/clean-models/
Maintaining crisp code with type aliases
For us lot, who strive to clean up and make our code look pretty, Kotlin has a nifty little feature. It's called type aliasing, and we can…
Show full content

For us lot, who strive to clean up and make our code look pretty, Kotlin has a nifty little feature. It's called type aliasing, and we can harness the functionality with the keyword typealias.

This week, we will be seeing where and how type aliasing makes sense and how to start using type aliases in our Kotlin based projects right away.

Type aliases, like a.k.a.?

For those who are new to the concept of type aliases, here's a quick primer:

A type alias is like another name for one of our existing types to make it look and resolve differently in our code.

Typealias or also known as

Take this as an example:

To declare a list of users, we generally write List<User>. What if, we want to make this declaration look more readable and natural like Users or UserList?

Traditionally, we would declare a plain model class to mask the less attractive List<User> to something like Users. Kind of like this:

data class Users(val userList: List<User>)

With type aliases, we can have the same result with less burden and no extra classes.

When I say less burden, what I'm trying to mean is that type aliases don't add a new type to our project. Therefore, there is no additional heap allocation, as there is no class initialisation.

Also, type aliases have the exact behaviour of the underlying type. Whatever our original class can do, a type alias can as well.

The aliasing process is straightforward

For our list of users, we can declare a type alias as the one below:

typealias Users = List<User>

This little declaration allows us to use our new Users type exactly like a list. Therefore, we can call list methods like add() on Users and even use cool Kotlin features like subscripts.

Take a look at the following code snippet:

typealias Users = MutableList<User>
    
val users: Users
users.add(User(name = "Rahul"))
    
println(users[0])

While this might not look much of an improvement apart from the initial fancy Users type, this is one of those little things which makes our code read like sentences.

Apart from this, we can level up our type aliasing game to cases such as:

Accommodating conflicting class names

Another use case where type aliases shine out is while importing two or more classes with the same name but placed in different packages.

You might have come across situations where some of your class names conflict with classes from a framework that you are using.

For Android developers, a typical example is Android's View class.

If we were to create our very own View class, we are at the complete liberty to do so, but with the tradeoff that we can't refer to both of them as View in a single class or file.

We have to refer one of them with their fully qualified name, like this:

fun compareViews(androidView: android.view.View, appView: View)

For cases similar to this, we can use type aliases to mask the framework's classes with a different name, such as:

typealias AndroidView = android.view.View

Now, instead of relying on the fully qualified class names to differentiate our classes, we can have readable names like:

fun compareViews(androidView: AndroidView, appView: View)

Doesn't it look better now?

A note of caution though

Type aliases don't create new types. I repeat type aliases are just a different name, just like you might have two names, one formal and the other, your super-cool spy name.

Why does knowing this matter?

Because type aliases don't mean type safety, they are like caskets for your types but identical to one another.

Consider this example, suppose we are building a maps function which accepts a latitude and longitude to display a map of the place:

fun showMap(latitude: Double, longitude: Double)

We can make this function more readable by adding type aliases to separate the latitude from the longitude.

typealias Latitude = Double
typealias Longitude = Double
    
fun showMap(latitude: Latitude, longitude: Longitude)

While this above snippet will compile and run just fine, we can still easily pass a Longitude object as latitude to the function, and the compiler won't budge.

val latitude: Latitude = 12.7
val longitude: Longitude = 88.5
    
showMap(longitude, latitude)

The reason behind this is although we aliased the Double type into "apparently" two new types, Kotlin didn't actually create the types Latitude and Longitude.

It just let us use Double by the names Latitude or Longitude. Therefore, the type Latitude is precisely the same as the type Longitude. They're both Double underneath.

If we open up the equivalent Java file of our Kotlin code, we will see that the none of our type aliases are present in the Java code. They were all replaced with their actual types when Kotlin compiled our code.

Also, any extension function or property we add to our type aliases will reflect in all instances of the underlying type.

For type safety, one way is to create model classes like this:

data class Latitude(value: Double)

Another way is to use Kotlin's inline classes. We will discuss more on this topic in a later article.

Common places where we can type alias

Masking lambdas in our callbacks:

typealias Result<T> = (T) -> Unit
    
fun fetchData(callback: Result<String>)

Marking nullable types:

typealias MaybeBook = Book?

Make nested classes look great:

typealias DialogBuilder = AlertDialog.Builder
    
val dialog = DialogBuilder().build()
I like type aliases because...

Although at first, they might seem to abstract away the actual types making it hard to know what's going on in the code, they are not that bad.

If we ever want to find out what the real type is, we can ⌘/Ctrl + Click on the alias to get to the declaration point. Also, we can see the underlying type in the autocomplete section while referring to the type alias name.

Peek underlying type on auto-complete

Over time, it's something we get used to and keeps our codebase comfortable to read through and understand for us and also our teammates.

For me, one of the main things I use type aliases for is masking lambdas as I showed before. With auto-suggest to help, it's easy to glide through writing lambdas using type aliases in a few keystrokes.

One more thing

We can only add type aliases at the top level in our Kotlin file. Therefore, unlike Swift, we cannot declare a type alias inside a class or an interface.

The following code won't compile and give us a compile-time error:

class OkKotlin {
    typealias SuperInt = Int
}

However, this one will work just fine:

typealias SuperInt = Int
    
class OkKotlin {
    val superInt: SuperInt
}

This is the only major drawback when using type aliases as we have to declare them at the top-level instead of scoping out to classes.

We are, however, free to scope module or file-level access by using the regular visibility modifiers like private and internal.

Now that you have witnessed the magic of type aliasing, will you be refactoring your code with type aliases anytime soon?

Here's a sketch note on the topic

Kotlin type alias sketch note

https://okkotlin.com/typealias/
Type-safe time calculations using Duration
Time calculations have always been a sensitive topic in most programming languages. Kotlin is no exception. If we have a function which…
Show full content

Time calculations have always been a sensitive topic in most programming languages. Kotlin is no exception.

If we have a function which accepts a time value to calculate a duration, it's challenging to enforce a proper unit that the caller must follow.

Starting from Kotlin 1.3.50, we can now make use of the Duration class to have worry-free time calculations in our programs. Let's see how that works.

Accepting time as a Long value is broken

The most common approach to store and work with time values is to have the time converted into milliseconds and stored into a Long variable.

While this works fairly when we are dealing with internal code, working on our own mostly, as soon as we expose some API which accepts a time for a teammate to use or general public, cracks appear.

Take this function as an example:

fun retryBackup(after: Long) {    
    // Retry data backup after a given millis of time
}

It's quite safe to say that this function is not type-safe. Although it accepts a Long parameter, that Long value can be anything.

Frustration of using Long for time

We can pass the value as milliseconds, or minutes, or days and the program would compile and run just fine. However, our calculations would be skewed.

The reason behind this is inside the function, we are expecting a time in milliseconds for our calculations. Therefore, if we need to retry the backup after 6 hours, we need to first convert 6 hours to its equivalent milliseconds and then pass the value.

This is not obvious to the caller when calling the function. The after parameter is just a Long . A Long value doesn't automatically equate to milliseconds. It can represent any unit of time.

Sure, we can improve the readability of our function by renaming the parameter to afterTimeInMillis but that is merely an indication to the caller, not safety.

We can still wrongly pass 6 as the value and the backup will be retried after 6 milliseconds instead of 6 hours.

Kotlin has a better way

Kotlin, in it's 1.3.50 release, introduced a new class called Duration. We will use this class to accept time in a type-safe way.

Quick definition:

The time to read this article can be represented by a duration

A Duration represents the amount of time between two instants. Like, 1 second, 2 hours, 5 minutes and so on.

Now, coming back to our previous function, retryBackup , to make it type-safe, we can swap out the Long parameter with a Duration and extract a milliseconds value from the supplied duration to work with.

Like this:

fun retryBackup(after: Duration) {    
    val millis = after.toLongMilliseconds()    
    // Retry data backup after a given millis of time
}

There's just a tiny hiccup though.

If we try to run this code, it won't compile. The compiler will complain that we need to mark our function with an ExperimentalTime annotation.

This because Duration isn't mature yet and to use it, we need to tell the compiler that we are okay with using an experimental feature.

Therefore, our final code will look like this:

@ExperimentalTime
fun retryBackup(after: Duration) {    
    val millis = after.toLongMilliseconds()    
    // Retry data backup after a given millis of time
}

Hang on a second, we still haven't talked about how this approach is type-safe. It is type-safe because we now need to specify a Duration with a proper time unit when calling the function, like this:

retryBackup(after = 6.hours)

Try passing a Long or an Int as a parameter. You will get a compile time error. This approach, apart from being type-safe, is much more readable too.

The standard library provides a bunch of handy extension properties on Int, Long, and Double values to create durations easily like we did before (6.hours).

Similarly, we can convert a Duration to it's equivalent milliseconds or nanoseconds by calling the methods toLongMilliseconds() and toLongNanoseconds() respectively.

If you have used Ruby on Rails, this sort of pretty syntax might seem familiar to you.

Calculating relative time

A duration is just a representation of an amount of time. It's not a timestamp.

In cases where we want to get a relative time like "1 day from now", we need to add the current time to our duration.

Since making this computation over and over again is a hassle, we can create a reusable extension property on the Duration class to ease our job.

The following extension property will compute a relative duration from the current time:

@ExperimentalTime
val Duration.fromNow
    get(): Duration {
        val currentDuration = System.currentTimeMillis().milliseconds
        return this + currentDuration
    }

One great thing about the Duration class is that all common operations like addition, subtraction, multiplication, etc are supported. Therefore, we can easily add the current elapsed duration with our offset and get a final computed duration.

Now, we can use this property to pass a relative timestamp instead of a duration value, like this:

runBackup(on = 1.days.fromNow)
Experimenting in production?

As we saw earlier, Kotlin's Duration APIs are at an experimental stage. So, the question is, will it be a good idea to use this in our production apps?

I would suggest not to use this API in a large project right now. Whatever code we discussed in this article might be invalidated in a later release.

Navigating the codebase and changing each usage will be a frustrating task.

For small hobby projects, it's perfectly fine to use these APIs because even if they change, your project might be fine with a couple of changes here and there.

Try it, maybe?

It feels nice to see how Kotlin is shaping up to be a language focused on developer happiness like Ruby. The duration API is another step in that direction.

Why don't you try out this new language feature?

Here's a sketch note on the topic

Sketch note Kotlin's Duration API

https://okkotlin.com/duration/
Introducing OkKotlin
Kotlin has been around for quite a few years. Like any other excited developer, I picked it up right after Google announced first-class…
Show full content

Kotlin has been around for quite a few years. Like any other excited developer, I picked it up right after Google announced first-class support for Kotlin for Android app development.

Kotlin sketch

Using the language and reading articles on it, I wasn't convinced that there couldn't be a better publication on the language.

A lot of publications leaned towards hands-on tutorials with Kotlin, mostly on the transition from Java. A good number focused on Kotlin from the perspective of an Android developer. They are doing an outstanding job in those niches.

I wanted to do something different.

Reading blogs like Swift by Sundell and Flavio Copes for over a year, I wanted to take a similar approach.

Pick out specific language feature or aspect and discuss on that, casually — no tutorials on how to get stuff done. There's plenty already.

What I want to do is to have an open discussion on Kotlin topics and show you some cool tricks that I have learnt while writing Kotlin code for over two years.

And that was the primary motivation behind starting this publication. Share my knowledge with the community by publishing one article every Sunday.

If you are looking for a similar publication, you have come to the right place. Bookmark this site or subscribe to the RSS feed to get notified whenever I publish an article.

You can also subscribe to the monthly newsletter, which will cover all things OkKotlin and more. Read the newsletter page for more information on that.

That said, I will try to do justice to this idea by putting up my best work, every single week, hoping that you will join me on this journey.

https://okkotlin.com/introduction/