Kotlin has type inference. This means you don’t always have to be explicit about the type an object or variable has. Follow along with this demo by starting a new Kotlin Playground session, or any other Kotlin development environment of your choice. Here’s an example where a variable is created without specifying the type:
val amount = 200
This syntax is common to a lot of dynamic programming styles for initializing a variable. But Kotlin isn’t a dynamic programming language. It’s static. So, a variable will always have one type throughout the duration of the program execution.
To determine the type assigned to a variable and how Kotlin identifies it, print out the class of the variable:
val amount = 200
println(amount::class.simpleName)
According to the program output below, the variable is of type Int. Kotlin automatically inferred the type of the variable based on the value and initialization method used. This automatic process of determining the type of a variable is called type inference, and it’s a helpful feature because it allows Kotlin to make intelligent guesses for you. If you wanted to specify this as a float, you’d add ‘f’ to the number:
val amount = 200f
println(amount::class.simpleName)
As you can see, the assigned type is Float. What if it should be a double instead? You could specify a decimal precision.
val amount = 200.0
println(amount::class.simpleName)
Type inference is efficient. But, if you need to explicitly specify the type, you only need to follow the name of the variable with a colon and the type. Specify the amount as a Float:
val amount: Float = 200f
println(amount::class.simpleName)
The specified type and the initialization data will have to match. Otherwise, you get an error:
val amount: Double = 200f
println(amount::class.simpleName)
The error reads: “The floating-point literal does not conform to the expected type Double”.
Checking Types
If you’re unsure of a variable’s type, you can use the is operator to check if the variable is of a particular type. Use it to check if “Bob” is a string:
val name: Any = "Bob"
val isString = name is String
println("Is name a String? " + isString)
If this check is true, Kotlin will go ahead and cast the variable to the verified type. You can then use the variable as the intended type within that context. In this example, you call the String class’ uppercase method on the variable because the check confirms it’s a String:
val name: Any = "Bob"
if (name is String){
println(name.uppercase())
}
This is called smart cast. It’s important to note that Kotlin is able to do this because the value is immutable. If it wasn’t, Kotlin couldn’t be so sure about the type of the variable. Being mutable and nullable means the value could change become null during the course of the program execution. For this reason, smart casting works with immutable types.
Kotlin isn’t completely in charge of type casting. You can do it yourself using the as operator. In this example, name is explicitly declared as Any. But, since it’s actually a String in implementation, looking at the initialization data, it’s cast to a String.
val name: Any = "Bob"
val firstName = name as String
println(firstName::class.simpleName)
In a real program, you may have no idea what a type is. So, using this method to assign a type to a variable is risky. The data has to be the exact type you’re casting to, otherwise you’ll get an error. Cast an Int to a String and check the results:
val amount: Any = 2
val result = amount as String
Run it. You get a ClassCastException. You might say that’s a bit harsh, and you’re right. This type of casting is an unsafe cast. To safe cast a variable to a type, use the ‘?’-appended form of as, as?, instead. This way, if the cast fails, your type receives a null value. That means it forces your variable to become nullable:
val amount: Any = 2
val result = amount as? String
println(result)
Now, that’s safer.
Strings
Strings are a common data type in most programs and programming languages. Strings represent text. In Kotlin, they’re made of a sequence of characters surrounded by double quotes. Being a sequence means you can iterate over the items that make up the sequence. Iterate over the following string:
val name: String = "Harry Potter"
for (char in name){
println(char)
}
Strings are final by default in Kotlin. final means that once created, a String can’t be modified. One immediate implication of using strings is the use of memory. Having too many Strings in your program will cause your program to use or claim memory quickly. This could force the program responsible for managing the memory for programs to work more often than it should.
To create a new String out of another, you can use concatenation. This requires the use of the plus operator +:
val fruits = "Apples" + " & " + "Oranges"
println(fruits)
Or the plus() function:
val fruits = "Apples".plus(" & ").plus("Oranges")
println(fruits)
Every String method that operates on a string creates a new string with the updated value.
Kotlin String Interpolation and Templates
Kotlin has a special feature that evaluates code within a string. After evaluation, Kotlin converts the result to a string, if it isn’t one already. It then concatenates the evaluation result with the rest of the string. The result is added at the original location of the expression in the string literal.
This convenient conversion reduces the code required to update and use a string. You begin the expression with the dollar sign - ‘$’. If the expression contains many terms, you surround the expression with curly braces. Here’s an example:
val apples = "Apples"
val oranges = "Oranges"
val fruits = "$apples & $oranges"
println(fruits)
For longer expressions that need curly braces, include them this way:
val apples = 2
val oranges = 3
val fruits = "There are ${apples + oranges} fruits in total."
println(fruits)
In a multiline string, backlash escaping is not allowed. You instead have to put the character to simply add the character or put it in single quotes in between the curly braces and the $ sign. See this example that showcases both methods:
val amount = 25
val chat = """
Ann: How much does this book cost?
Bryan: This book costs $${amount}.
And you get a discount of ${'$'}9.99
"""
println(chat)
Again, you could use longer expressions within the curly braces and even spread them on multiple lines when using a multiline string:
val lowest = 45
val cash = 200
val books = 20
val chat = """
Ann: With $$cash how many books can I afford?
Bryan: ${ if (cash > lowest) 20 else 10 } books.
Ann: ${
if (books > 10) "Awesome!"
else "That's OK!"
}
"""
println(chat)