A Day with Kotlin

What Kotlin has that Java does not.

Rajendra Uppal
Software Architecture

--

So, I was hearing a lot about Kotlin lately and decided to give it a try. It will be fun learning about a new language and maybe I find it useful for some product or app.

Kotlin’s official documentation is great and there are many introductory articles to Kotlin language on medium, so I won’t be explaining the basics and syntax but wanted to present some unique features that Java doesn’t have and makes Kotlin stand out.

1. Null Safety

One of the most common pitfalls of many programming languages including Java, is that accessing a null reference would result in a null reference exception. In Java, this is known as NullPointerException or NPE.

Kotlin’s type system eliminates the danger of null references from code. Kotlin would throw NullPointerException only if:

  • programmer calls throw NullPointerException(); explicitly
  • usage of the !! operator
  • some data inconsistency with regard to initialization
  • Java interpolation

Kotlin distinguishes between null (nullable references) and non null (non-null references) types. Types are non-null by default and can be made nullable by adding a ?

var a: String = "abc"  // non-null reference by default
a = null // compile time error!
// now if you call a method on a, its guaranteed not to cause a NPE
var len = a.length // fine
var b: String? = "abc" // nullable reference
b = null // okay
// but if you access same property on b
// that won't be safe and compiler throws an error!
var len = b.length // error: b can be null
// you can use safe call operator ?. though
var len = b?.length // okay, this will return the length
// if b is not null and will return null otherwise

2. Smart Casts

Kotlin tracks your logic and auto-casts types if possible. No more instanceof checks followed by explicit casts as in Java.

var s = "abc"
if (s is String)
println(s.length)

Kotlin keeps track of is checks and you don’t have to use explicit cast operators.

fun demo(x: Any) {
if (x is String)
println(x.length) // x is automatically cast to String
}

3. String Templates

Strings may contain template expressions i.e. code that is evaluated and its result is concatenated into the string.

A template expression starts with a $ sign and can be a simple name like this:

val n = 10
println("n = $n") // prints n = 10

or can be an arbitrary expression in braces like this:

val s = "abc"
println("$s.length is ${s.length}") // prints abc.length is 3

you can evaluate expressions like this:

val a = 3
val b = 5
println("Sum of $a and $b is ${a + b}")
// prints Sum of 3 and 5 is 8

4. Properties

Classes in Kotlin can have properties. No need to bloat your code with explicitly written getters and setters as in Java. Properties can be declared mutable using var keyword or read-only using val keyword.

class Address {    var name: String = ""
var street: String = ""
var city: String = ""
var state: String? = ""
var zip: String = ""
}

Usage:

fun copyAddress(address: Address): Address {    val result = Address() // there is no new keyword in Kotlin!
result.name = address.name // accessors are called
result.street = address.street
// ...
return result
}

5. Primary Constructors

A class declaration in Kotlin consists of:

  • class name
  • class header (primary constructor and other type parameters)
  • class body

A class in Kotlin can have a primary constructor like so:

class Person(firstName: String) {}

and you can use initalizer blocks as:

class Customer(name: String) {    val customerKey = name.toUpperCase()}

There are secondary constructors also, check out.

6. Type Inference

Kotlin infers data types of variables and properties. So, you can omit types wherever you feel it will improve readability.

val a = "abc"                         // type inferred to String
val b = 4 // type inferred to Int

val c: Double = 0.7 // type declared explicitly
val d: List<String> = ArrayList() // type declared explicitly

Explicit conversions are also supported. Smaller types are NOT implicitly converted to bigger types. This means we cannot assign a value of type Byte to an Int variable without an explicit conversion as follows:

val b: Byte = 1  // fine, literals are checked statically
val i: Int = b // Error!
// use explicit conversions to widen numbers
val i: Int = b.toInt() // Okay, explicitly widened

Kotlin infers types from the context and arithmetical operations are overloaded for appropriate conversions. e.g.

val num = 1L + 3  // Long + Int => Long

7. Ranges

Range expressions in Kotlin are written with .. , in and !in operators.

for (i in 1..10) // i ∈ [1, 10] both inclusive
println(i)

If you want to iterate in reverse order. use downTo() function as so:

for (i in 4 downTo 1)
print(i) // prints 4321

Iterating over numbers in arbitrary step instead of default 1, use step() function as so:

for (i in 1..4 step 2)
print(i) // prints 13
for (i in 4 downTo 1 step 2)
print(i) // prints 42

Want to exclude last element? use until() function.

for (i in 1 until 10) // i ∈ [0, 10) 10 is excluded.
print(i) // prints 123456789

See other important function here. That’s why I like to say that Kotlin is Python of the Java world!

8. Extension Functions

Kotlin provides you the ability to extend an existing class with new functionality without having to inherit from the class or use any kind of design pattern such as Decorator. This is done via special declarations called extensions. Kotlin provides extension functions and extension properties.

Example of adding a swap functionality to MutableList<Int> as:

fun MutableList<Int>.swap(index1: Int, index2: Int) {
val temp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = temp
}
// now you can call such a function on any MutableList<Int> object
val numbers = mutableListOf(1, 2, 3)
numbers.swap(0, 2)
println(numbers) // prints [3, 2, 1]

9. Operator Overloading

Java doesn’t support operator overloading. Kotlin does. When you use an operator in Kotlin, its corresponding member function is called. e.g. expression a + b transforms to a.plus(b) under the hood. plus function is overloaded to work with various Kotlin basic types and String.

You can overload operators for your own defined types. e.g.

class Point(val x: Int = 0, val y: Int = 10) {    // overloading plus operator
operator fun plus(p: Point): Point {
return Point(x + p.x, y + p.y)
}
}// now you can add 2 Point's as
val p1 = Point(3, -8)
val p2 = Point(2, 9)
val sum = Point()
sum = p1 + p2
println("sum = (${sum.x}, ${sum.y})") // prints sum = (5, 1)

Here the plus function is marked with operator to tell the compiler that +operator is being overloaded here. Expressionp1 + p2 is transformed into p1.plus(p2) under the hood.

10. Destructuring Declarations

Its convenient to destructure an object into a number of variables. e.g.

val (name, age) = person

This is called destructuring declarations. A destructuring declaration is compiled down into following code:

val name = person.component1()
val age = person.component2()

Destructuring declarations also work in for-loops as:

for ((a, b) in collection) { ... }

Probably the nicest way to traverse a map is

for ((key, value) in map) {
// do something with key and value
}

Destructuring declarations also helps in returning 2 values from a function. e.g.

data class Result(val result: Int, val status: Status)
fun function(...): Result {
// other code
return Result(result, status)
}

Other than above mentioned major features, Kotlin also supports == (structural equality) and === (referential equality), default arguments, named arguments, when expression as a better switch case statement, lambdas and higher order functions.

Conclusion

Overall, I think Kotlin is a great language, safe by default and very pleasant to work with. I have just shaved the tip of the iceberg here, there is a lot more to cover. If you are a Scala developer, you will probably not find many new things in Kotlin. But if you are a Java developer and are tired of the boilerplate and all the ceremonies before you get to do any real work, then Kotlin is for you.

Cheers!

--

--

Rajendra Uppal
Software Architecture

Software Engineering Leader, Formerly at Microsoft, Adobe, Studied at IIT Delhi and IIT Kanpur. www.linkedin.com/in/rajendrauppal