Top 10 Kotlin Stack Overflow questions

This content was originally published as a series of articles on zsmb.co (with some runnable code snippets!).


I am currently defending the third place on the top users list of the Kotlin tag on StackOverflow, and I wanted to make use of the bragging rights this gives me while I can. The best way I found is to have a look at some of the most frequently asked questions about Kotlin on StackOverflow.

1. Array<Int> vs IntArray

What's the difference between Array<Int> and IntArray?

This is a simple one to start with.

Array<Int> uses the generic Array class, which can store a fixed number of elements for any T type. When using this with the Int type parameter, what you end up in the bytecode is an Integer[] instance, in Java parlance.

This is what you get when you use the generic arrayOf method to create an array:

val arrayOfInts: Array<Int> = arrayOf(1, 2, 3, 4, 5)  

IntArray is a special class that lets you use a primitive array instead, i.e. int[] in Java terms. (There are similarly named classes for the other primitive types as well, such as ByteArray, CharArray, etc.)

These can be created with their own (also non-generic, like the class itself) intArrayOf factory method:

val intArray: IntArray = intArrayOf(1, 2, 3, 4, 5)  
When to use which one?

Use IntArray by default. Primitive arrays are more performant, as they don't require boxing for every element. They are also easier to create - an Array<Int> requires a non-null value for each of its indexes, while IntArray initializes them automatically to 0 values. Here's an example of this, using their constructors:

val intArray = IntArray(10)  
val arrayOfInts = Array<Int>(5) { i -> i * 2 }  

Use Array<Int> when you're forced to use the Array class by an API, or if you need to store potentially null values, which an Array<Int?> is of course able to do. If you need to create an Array<T?>, the simplest way is using the arrayOfNulls function of the standard library:

val notActualPeople: Array<Person?> = arrayOfNulls<Person>(13)  

2. Iterable vs Sequence

What's the difference between an Iterable and a Sequence?

Iterable is mapped to the java.lang.Iterable interface on the JVM, and is implemented by commonly used collections, like List or Set. The collection extension functions on these are evaluated eagerly, which means they all immediately process all elements in their input and return a new collection containing the result.

Here's a simple example of using the collection functions to get the names of the first five people in a list whose age is at least 21:

val people: List<Person> = getPeople()  
val allowedEntrance = people  
        .filter { it.age >= 21 }
        .map { it.name }
        .take(5)

First, the age check is done for every single Person in the list, with the result put in a brand new list. Then, the mapping to their names is done for every Person who remained after the filter operator, ending up in yet another new list (this is now a List<String>). Finally, there's one last new list created to contain the first five elements of the previous list.

In contrast, Sequence is a new concept in Kotlin to represent a lazily evaluated collection of values. The same collection extensions are available for the Sequence interface, but these immediately return Sequence instances that represent a processed state of the date, but without actually processing any elements. To start processing, the Sequence has to be terminated with a terminal operator, these are basically a request to the Sequence to materialize the data it represents in some concrete form. Examples include toList, toSet, and sum, to mention just a few. When these are called, only the minimum required number of elements will be processed to produce the demanded result.

Transforming an existing collection to a Sequence is pretty straightfoward, you just need to use the asSequence extension. As mentioned above, you also need to add a terminal operator, otherwise the Sequence will never do any processing (again, lazy!).

val people: List<Person> = getPeople()  
val allowedEntrance = people.asSequence()  
    .filter { it.age >= 21 }
    .map { it.name }
    .take(5)
    .toList()

In this case, the Person instances in the Sequence are each checked for their age, if they pass, they have their name extracted, and then added to the result list. This is repeated for each person in the original list until there are five people found. At this point, the toList function returns a list, and the rest of the people in the Sequence are not processed.

There's also something extra a Sequence is capable of: it can contain an infinite number of items. With this in perspective, it makes sense that operators work the way they do - an operator on an infinite sequence could never return if it did its work eagerly.

As an example, here's a sequence that will generate as many powers of 2 as required by its terminal operator (ignoring the fact that this would quickly overflow):

generateSequence(1) { n -> n * 2 }  
        .take(20)
        .forEach(::println)
Which one should I use?

Use Iterable by default. You will be creating intermediary collections, but these generally don't affect performance too badly. In fact, for small collections, they might be faster than the overhead that using a Sequence introduces.

Use a Sequence if you need to handle an infinite number of elements - this is something they are uniquely capable of doing. Consider a Sequence if you have very large collections to manipulate, and expect a performance gain from doing so lazily - perhaps you know that there are elements you won't need to process. As with always with performance advice, you'll have to benchmark your specific code to see if this really is the right choice for you.

Finally, use a Stream if you are going to be interoperating with Java code that already uses them. They work just fine in Kotlin (while Sequences do not work in Java).

3. Iteration with indexes

How can/should I iterate over a collection of items?

Here's probably everyone's first idea of how to do this after seeing the for loop syntax with ranges:

for (i in 0..args.size - 1) {  
    println(args[i])
}

Then you might find out that Array has a lastIndex extension property that's easier to read:

for (i in 0..args.lastIndex) {  
    println(args[i])
}

Then you realize that you don't actually need the last index, you just need to have an open ended range, which is what until creates:

for (i in 0 until args.size) {  
    println(args[i])
}

Of course, then again you'll find out that you can get this same range with the indices extension property:

for (i in args.indices) {  
    println(args[i])
}

But you can also iterate the collection directly instead of a range of indexes, with this syntax:

for (arg in args) {  
    println(arg)
}

Or you can go a bit functional and use the forEach function, passing a lambda to it that will do the work on each element:

args.forEach { arg ->  
    println(arg)
}

These are all very, very similar in terms of the generated code - in this case of iterating over an Array, they all increment an index variable and get elements by the index in a loop.

But if we were iterating a List instead, the last two solutions would instead use an Iterator under the hood, while the rest would still make a get call with each index. The Iterator approach here has the potential of being more efficient for certain collections1.

1 For example, iterating over a LinkedList would be an O(n^2) operation, as a LinkedList has O(n) lookup times. It wouldn't matter for an ArrayList, which has O(1) lookups, since it uses an Array to store its items.

Using the indices extension property is a close third in the race - it uses a for loop and looks up elements by index, but it has fairly clean bytecode compared to the three other methods before it.

What if I need the current item's index as well?

Firstly, there's the withIndex extension function that returns an Iterable of objects that can be destructured into the current index and element:

for ((index, arg) in args.withIndex()) {  
    println("$index: $arg")
}

However, there's also the forEachIndexed function that calls the provided lambda for each index and argument.

args.forEachIndexed { index, arg ->  
    println("$index: $arg")
}

Both of these functions use iterators for lists, but while the withIndex() solution uses an iterator for arrays too, the forEachIndexed is nicely optimized and uses indexes in that case.

4. SAM conversions

SAM conversions are a very frequent topic of questions. To address these, let's construct a single code example to show off various issues on.

We'll have an OnClickListener interface with a single method declared in Java:

public interface OnClickListener {  
    void onClick(Button button);
}

And a Button class which can be given a listener that's called for every click of the button:

public class Button {  
    public void setListener(OnClickListener listener) { ... }
}

The full syntax for creating an anonymous listener in Kotlin would look like this:

button.setListener(object: OnClickListener {  
    override fun onClick(button: Button) {
        println("Clicked!")
    }
})

Thanks to SAM conversion, you can also pass in just the inner braces and their contents in this case, as a lambda:

button.setListener {  
    println("Clicked!")
}
Why is my click listener not being called?

A common mistake when using SAM conversion is not directly putting the code you want to run inside your first set of braces which represent your lambda. This code will work as expected:

button.setListener {  
    println("Clicked!")
}

However, none of the following ones will.

This one gives the button a lambda that will create an anonymous instance of an OnClickListener every time the button is clicked, which is then just thrown away (never assigned anywhere, never invoked).

button.setListener {  
    object: OnClickListener {
        override fun onClick(button: Button) {
            println("Clicked!")
        }
    })
}

This one declares a useless local function in a very similar fashion:

button.setListener {  
    fun onClick(button: Button) {
        println("Clicked!")
    }
}
How do I refer to the anonymous instance if I create it with a SAM conversion?

Sometimes you need to refer to the listener instance itself when it's called, for example, you might want to remove it in some cases. In Java, you could reference the anonymous class with the this keyword. If you use SAM conversion, this is simply not possible. For these cases, you have to use the full object expression syntax:

button.setListener(object: OnClickListener {  
    override fun onClick(button: Button) {
        button.removeListener(this)
    }
})
Why is my SAM conversion complaining about a return type?

SAM conversions by their concise nature hide the required return types of the methods that they're overriding. For example, if the OnClickListener interface looked like this instead, with a boolean return to signify whether the click has been handled:

public interface OnClickListener {  
    public boolean onClick(Button button);
}

Then this implementation would no longer be valid:

button.setListener {  
    println("Clicked!")
}

You'd get the following error on the println statement:

Kotlin: Type mismatch: inferred type is Unit but Boolean was expected

This is a problem on the println statement because lambdas (somewhat controversially) implicitly return their last expression's return value, in this case, Unit. The fix of course is to add a statement that matches the required return type as declared in the interface:

button.setListener {  
    println("Clicked!")
    true
}
I can't use SAM conversions for Kotlin interfaces! What do I do now?

It often comes up that SAM conversions only work as described above if both the OnClickListener interface and the Button class (or more importantly, the method that takes the listene
If the interface is defined in Java, r parameter) are defined in Java.

If the interface is defined in Java, but the function that takes an instance of it is defined in Kotlin, you'll have to use a more explicit language construct, a SAM constructor:

button.setListener(OnClickListener {  
    println("Clicked!")
})

And if your interface is defined in Kotlin, you can do nothing but use a full object expression syntax:

Java interfaceKotlin interface
Java methodSAM conversionObject expression
Kotlin methodSAM constructorObject expression

The explanation in the documentation for this is that in Kotlin we have function types, and we should use those instead - however, doing so leads to occasional weird usage from Java code. Note that the table above doesn't mention usage from Java, since all of the above combinations can simply be used with lambdas there.

In conclusion, if you don't need to support Java, you can just use function types freely in Kotlin, perhaps with type aliases to make your types clearer. If you do have to interop with Java still, define your interfaces in Java, and if you can, also the methods that take these interfaces. This will give you the best experience in both languages.

5. Replacing static things

How can I make a function or variable static?

This turned out to be a way too long and boring topic to explain in a talk like this, but here's the basics quickly. If your class has "non-static" parts as well, place the "static" parts in a companion object:

class Foo {  
    companion object {
        fun x() { ... }
    }
    fun y() { ... }
}

If your class was completely static, you can also replace it with a singleton object:

object Foo {  
    fun x() { ... }
}

And if you don't want to always scope your calls as Foo.x() but want to just use x() instead, you can use a top level function:

fun x() { ... }  

Additionally, if you'll need to call these "static" parts from Java, look into using the @JvmStatic and @JvmName annotations to make those calls nicer. Here's a reference table for what the annotations do to Java calls:

Function declarationKotlin usageJava usage
Companion objectFoo.f()Foo.Companion.f();
Companion object with @JvmStaticFoo.f()Foo.f();
ObjectFoo.f()Foo.INSTANCE.f();
Object with @JvmStaticFoo.f()Foo.f();
Top level functionf()UtilKt.f();
Top level function with @JvmNamef()Util.f();

For variables, the same rules about where to place them apply, and so the the above annotations. Additionally, there's a @JvmField annotation that can be used with variables, plus the const keyword which optimizes calls to compile time constants by inlining their values to the call sites at compilation time. Here's the reference:

Variable declarationKotlin usageJava usage
Companion objectX.xX.Companion.getX();
Companion object with @JvmStaticX.xX.getX();
Companion object with @JvmFieldX.xX.x;
Companion object with constX.xX.x;
ObjectX.xX.INSTANCE.getX();
Object with @JvmStaticX.xX.getX();
Object with @JvmFieldX.xX.x;
Object with constX.xX.x;
Top level variablexConstKt.getX();
Top level variable with @JvmFieldxConstKt.x;
Top level variable with constxConstKt.x;
Top level variable with @JvmNamexConst.getX();
Top level variable with @JvmName and @JvmFieldxConst.x;
Top level variable with @JvmName and constxConst.x;
How can I declare a static initializer?

This is a simpler and much quicker question. If you need to run certain code just once for a class, you can use initializer blocks inside their companion object to do so - these will be translated to regular static initializers.

class X {  
    companion object {
        init {
            println("Static initialization!")
        } 
    }
}

Nullability

6. Smart casts on mutable properties

Why doesn't smart cast work on mutable properties?

Here's what the problematic code looks like:

class Dog(var toy: Toy? = null) {  
    fun play() {
        if (toy != null) {
            toy.chew()
        }
    }
}

toy is expected to be smart cast inside the if block from Toy? to Toy, as it has been checked for nullability. However, this error appears:

Kotlin: Smart cast to 'Toy' is impossible, because 'toy' is a mutable property that could have been changed by this time

The issue is that this Dog instance could be modified from another thread between the time the toy != null check is made, and the toy.chew() method is called. This could potentially cause a NullPointerException.

What can I do to make it work?

The issue doesn't exist if the property is not mutable. It's a good idea to make everything (both properties and variables) a val by default, and only make them mutable if you must.

If they really have to be mutable, using a local immutable copy solves the problem - smart cast works as expected on an immutable variable:

class Dog(var toy: Toy? = null) {  
    fun play() {
        val _toy = toy
        if (_toy != null) {
            _toy.chew()
        }
    }
}

But of course, there's a nicer way to make a temporary copy:

class Dog(var toy: Toy? = null) {  
    fun play() {
        toy?.let { 
            it.chew()
        }
    }
}

At this point, you should probably have noticed the obvious solution for this simple case of calling just a single function on the property in question:

class Dog(var toy: Toy? = null) {  
    fun play() {
        toy?.chew()
    }
}

But the solution using let works for the cases where you do more complex things after your null check.

7. null!!

Why exactly does null!! crash?

Here's some example code of a property which is meant to be non-null, but for some reason can't be initialized when the class is constructed. Putting !! after null lets the code compile, but at what cost? Any time an Episode is constructed, it will crash with a KotlinNullPointerException.

class Episode {  
    var airdate: Date = null!!
}

The problem here is that the !! operator is often perceived to be similar to the safe call operator ?., and therefore thought to not do anything in the code above, since there's nothing on its right hand side anyway. It's also sometimes thought to be a compile time signal to the compiler to "just let your code compile", which it is not.

Let's take a look at another code sample:

fun scheduleEpisode(airdate: Date?) {  
    airdate!!.getWeekday()
}

The most important point here is that the !! operator can exist and does its job without anything following it. While airdate is the first expression of the line, the next expression is not airdate!!.getWeekday(), but instead just airdate!!. The way this is evaluated is the following:
- If airdate is non-null, it returns airdate, but now as a non-nullable type, in this case, Date, which is why the getWeekday method can be then called without a safe call operator. - If airdate is null, it throws a KotlinNullPointerException.

You can think of !! as having the same functionality as an extension function like this would:

fun <T> T?.forceNonNull(): T {  
    if (this == null) {
        throw KotlinNullPointerException("Oops, found null")
    } else {
        return this as T
    }
}

So the previous usage of !! would be equivalent to this:

fun scheduleEpisode(airdate: Date?) {  
    airdate.forceNonNull().getWeekday()
}

Finally, let's get back to our original problem:

class Episode {  
    var airdate: Date = null!!
}

The issue should now be obvious. Before the value of the expression null!! is assigned to the property, it has to be evaluated, with throws the exception.

8. Platform types

How do I decide the nullability of a parameter when overriding a Java function? What are the consequences of each choice?

Let's return to our OnClickListener class defined in Java, with a single callback method.

public interface OnClickListener {  
    void onClick(Button button);
}

We'll assume that sometimes a valid Button instance isn't provided for the click event (perhaps the Button is disabled by the time the listener is called). We'll also forget to annotate these parameters in the Java code accordingly.

Let's override this interface in Kotlin - we'll end up with the following method signature if we let IDEA generate it:

class KtListener: OnClickListener {  
    override fun onClick(button: Button?): Unit {
        val name = button?.name ?: "Unknown button"
        println("Clicked $name")
    }
}

Since the Java method has no nullability annotations, the parameters of the Kotlin function will have a platform type, in this case, Button!. This means that it's up to us to decide (based on experience, or hopefully, documentation) whether the parameter received by the method can be null.

By default, it's safer to use the nullable types for all parameters, and suffer the restrictions that the compiler forces on us to handle these safely. This results in some extra code, but is always safe.

For parameters which are known never to be null, the non-nullable type can be used instead - both will compile. If the method does get called with a null value for a parameter we marked to be non-null, an injected null check will produce an IllegalArgumentException before any of the code in the method body would run, making this a slightly riskier choice. Of course, having a non-nullable parameter simplifies our code:

class KtListener: OnClickListener {  
    override fun onClick(button: Button): Unit {
        val name = button.name
        println("Clicked $name")
    }
}

Small bonus tip

9. Import aliases

How can I use multiple extension functions with the same name in a file?

Let's say you implement two different indent extension functions on the String class in two different packages. If this was an ordinary function, you could call it with a fully qualified package name, however, the syntax doesn't allow for it with an extension function - there's quite simply nowhere to put the package name:

"hello world".indent()

However, you can use the as keyword at the import statement to rename one (or both) of them, like so:

import com.example.code.indent as indent4  
import com.example.square.indent as indent2  

Which then lets you use each of them by their new names:

"hello world".indent4()

Another use case is that you could be using two classes with the same name from different packages in the same file (e.g. java.util.Date and java.sql.Date), and you don't want to use either of them by their fully qualified name. You could do the following here:

import java.util.Date as UtilDate  
import java.sql.Date as SqlDate  

Within this file, you can now refer to these classes by their aliases.

Wrap-up

10. Kotlin vs Java

Which one should I learn if I'm just starting to learn Android development?

❓ ❓ ❓ ❓ ❓ ❓ ❓ ❓ ❓ ❓ ❓

I'd consider nothing other than Xamarin. Don't waste your time on native development, it's 2018. /s


Anyhow, that's a wrap, thank you for reading this article, and see you on StackOverflow :)