If you have ever worked with Java (and depending on the version specifically) you may have noticed that the language did not have a keyword to explicitly declare a variable – until version 10 was released, in which Java developers started to have something like the below example:
var name = “David”;
Before that, the only possible way to declare a variable was via providing its type before its name, as demonstrated here:
String name = “David”;
Since its conception, Kotlin has “worried” about some of these gaps from the Java language, and has sought to provide a much more simplified, less verbose, and more intuitive programming experience.
Just like Java 10’s var keyword, Kotlin also provides us with the same ability to enable automatic type inference without having to explicitly tell the code which type it is. In this article, we are going to dive a bit deeper into this keyword, as well as the other two possible ways to declare variables and constants in Kotlin.
Read: Introduction to Kotlin
Type Inference in Kotlin
Kotlin was born with inferred typing, whereas Java grew to a point in which it had to allow it, alongside the previous explicit type declaration style. But what does that mean in practical terms? Let’s take a look back at the previous example:
var name = “David”;
Here, both languages take action backstage to infer that name’s type is a String because the value that is assigned to it is very explicit. Since the var keyword tells the language that it is a variable, you may guess whether it accepts a variable that is nullable (i.e. it is optional and accepts null values) or not.
In Java, depending on the scope in which the variable is defined, if no value is provided, the variable is either initialized with its default value (each primitive type has one, objects default to null) or throws a compilation error stating this need.
For example, take the following code snippet in Java:
String name; void print() { String name; System.out.println(name); // error: variable name might not have been initialized System.out.println(this.name); // prints null }
The above is a good example demonstrating how a local versus global variable works differently in terms of default values versus non-initialization compilation errors.
However, when it comes to the var keyword, that example can not apply because it is only allowed for local scopes, and it does require the variable to be initialized:
void print() { var name; // error: cannot infer type for local variable name System.out.println(name); }
The same piece of code from the previous example could be translated as follows to Kotlin code:
var name: String? = null fun print() { var name // This variable must either have a type annotation or be initialized println(name) println(this.name) }
The first thing to notice in the above examples is how different the global variable is in Kotlin. Kotlin does not allow nullable types by default as Java does. Instead, if you are willing to make a variable optional, you have to explicitly say so by providing its type followed by a question mark (?) and its default value – yes, a variable can be declared to accept null values but also be initialized with another one, as shown here:
var name: String? = “”
The same rule applies to every single place you create variables, including local ones, as you could see based on the error thrown by the internal name var. With that said, once we update the code to be fully compilable as shown below, the expected results are printed:
var name: String? = "David" fun print() { var name: String? = null println(name) // prints null println(this.name) // prints David }
Read: Getting Started with Kotlin Coroutines
Read-only Values in Kotlin
Just like we have in Java, constants are necessary for various purposes. Previously, to define that a variable would be read-only, we needed to explicitly add the final keyword to it:
final String name = “”;
As a consequence of that, the compiler immediately asks for a value to initialize it, whether it is coming from the constructor or being assigned directly.
With Kotlin, the same applies, but with a val. The val keyword is a shortcut that leads to the same behavior, but with way less verbosity:
val name = “”;
Note that the type inference also takes place for val, meaning that the type is optional in that case. These types of values are very useful when building data classes that handle immutability in Kotlin:
data class Person(val name: String, val age: Int?)
As observant developers may have noticed, you can also take null values the same way – they can be initialized to hold a constant null value:
Person("David", null)
Read: The Top Java IDEs for 2022
Constants in Kotlin
Finally, we have the constants. Wait, haven’t we just seen constant values in Kotlin? Yes, kind of – but with a difference. Just like in Java, when you want a constant to be known at compile-time and statically available everywhere, developers need to add another keyword: static:
static final String NAME = “David”;
The convention also establishes that constants in Java must be in uppercase. In Kotlin, constants follow the same principle, but their declaration is simplified, as shown below:
const val NAME = “David”;
Yes, the val keyword is necessary alongside const, and the type inference takes place the same way as before. Constants can also take advantage of the visibility accessors just like in Java:
private const val NAME = “David”;
In this case, the constant would be available only to the Kotlin file context in which it was declared.
Conclusion to var, val, and const in Kotlin
This has been a very brief, but essential, look at how the var, val, and const keywords work in Kotlin and how Java developers, in particular, can easily understand their usage, since they are the basis for pretty much all coding you will do in the language.
Read more Java programming tutorials and how-tos.