1. Introduction

In this tutorial, we’ll be outlining the key differences between the const, var, and val keywords in the Kotlin language.

To put these keywords into context, we’ll be comparing them to their Java equivalents.

2. Understanding Typing

To understand these keywords, we have to understand two of the major categories of type systems a language can follow – manifest typing and inferred typing.

2.1. Manifest Typing

All languages offer a range of primitive data types to store and manipulate data within a program. Programming languages following the manifest typing discipline must have their data types explicitly defined within the program.

Java, up until version 10, strictly follows this discipline. For example, if we want to store a number within a program, we must define a data type such as int:

int myVariable = 3;

2.2. Inferred Typing

Unlike Java, Kotlin follows the inferred typing discipline. Languages supporting type inference automatically detect data types within the program at compile-time.

This detection means that we, as developers, don’t need to worry about the data types we’re using.

3. var

Firstly, we’ll start with var, Kotlin’s keyword representing mutable, non-final variables. Once initialized, we’re free to mutate the data held by the variable.

Let’s take a look at how this works:

var myVariable = 1

Behind the scenes, myVariable initializes with the Int data type.

Although Kotlin uses type inference, we also have the option to specify the data type when we initialize the variable:

var myVariable: Int = 1

Variables declared as one data type and then initialized with a value of the wrong type will result in an error:

var myVariable: Int = b //ERROR!

4. val

Kotlin’s val keyword works much in the same as the var keyword, but with one key difference – the variable is read-only. The use of val is much like declaring a new variable in Java with the final keyword.

For example, in Kotlin, we’d write:

val name: String = "Baeldung"

Whereas in Java, we’d write:

final String name = "Baeldung";

Much like a final variable in Java, a val variable in Kotlin must be assigned a value as it’s declared, or in a Class constructor:

class Address(val street: String) {
    val name: String = "Baeldung"
}

5. const

Like val, variables defined with the const keyword are immutable. The difference here is that const is used for variables that are known at compile-time.

Declaring a variable const is much like using the static keyword in Java.

Let’s see how to declare a const variable in Kotlin:

const val WEBSITE_NAME = "Baeldung"

And the analogous code written in Java would be:

final static String WEBSITE_NAME = "Baeldung";

5.1. Constant Inlining

As of Kotlin 1.1, the Kotlin compiler inlines the const val values into the locations where they’re used. For instance, let’s consider a simple example:

const val VALUE: String = "constant"

fun main() {
    println("$VALUE is inlined")
}

At first glance, we might think that the Kotlin compiler gets a static field value from a class and then concatenates it with the ” is inlined” text. However, since const vals are inlined, the compiler will copy the “constant” literal wherever the VALUE constant is used. This constant inlining is much more efficient than getting a static value from a class.

To verify that the inlining actually happens under-the-hood, we can check out the bytecode. First, we should compile the Kotlin file using kotlinc:

$ kotlinc Main.kt

Then, using javap, we can take a peek at the generated bytecode:

$ javap -c -p -v MainKt
// truncated
0: ldc           #16                 // String constant is inlined
2: astore_0
3: iconst_0
4: istore_1
5: getstatic     #22                 // Field java/lang/System.out:Ljava/io/PrintStream;
8: aload_0
9: invokevirtual #28                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
12: return

As shown above, at index 0, the “constant” literal is copied for concatenation. So, there’s no getstatic to a fetch a value from a static field in a class.

The bottom line is that *even though the const vals may look like static fields, they’re not implemented as public static final fields*. Put simply, the const val is just a compiler illusion.

6. Conclusion

In this article, we’ve taken a quick look at the difference between manifest and inferred typing.

Then, we looked at the difference between Kotlin’s var, val, and const keywords.