7 minute read

Part 1 of a series of posts on why coding in kotlin makes so much sense over java.

A kotlin function

Hello wonderful people,

Over my 8 years of experience as a coder/Quality engineer the language which gave me the comfort of feeling at home was and still is “Python” 🐍 till date.

It allowed me to truly solidify concepts in programming as well as gave me the freedom to write concise code quickly to turn my ideas into executable logic and it was a ton of fun.

The dynamic nature/duck typing, No worries about types, use of higher order functions and focus on writing readable and explicit code while solving problems was something which i really adore in the language.

When I switched jobs a year back. Most of the test automation code in my new company was written in Java. And even though I quickly started learning and became fluent in the language, Java and its constructs felt too verbose and syntax heavy to me. I found myself spending more time worrying about types all the time rather than actually getting code out and though i was productive with it in a short amount of time. It never felt ease like Python.

Until i discovered Kotlin close to 3 months back. And this is the story of how Kotlin changed my life in a world full of Java code. 🙂

With that pretext. Let’s dig into what are some of the features of Kotlin language which simplify our life as a programmer in the JVM world.

In researching for this post, I went through multiple blogs and most of these examples are from a talk given at Google IO by none other than the lead kotlin language designer Andrey Breslav 🙌

Classes

1.1 Concise classes with automatic Getters and Setters

One of the trademark constructs in Java is a bean/POJO which on a high level is primarily a bunch of Getters/Setters and constructors to represent an object.

Let’s say we wanted to represent a Person having a name and age. Below is how we would write this in Java.

And here is the equivalent code in Kotlin: 😆

Kotlin allows us to define name and age as properties in the constructor itself with automatic getters and setters generated. Pretty slick right?

Also Kotlin allows to directly access the properties via their name. Avoiding the whole getProperty() or setProperty() syntax. So much less clutter.

1.2 Data Classes are cheap and concise

Classes in Kotlin are cheap to create and can be created in any .kt file without requiring the File name to match the class name itself and we have a modifier called as data which unlocks so much additional features out of the box.

Let’s see an example of this:

Let’s examine the above code:

  • parseName is a function that takes a full name and returns a list of separated first and last names
  • In main function we are unpacking them and asserting if the function did its job correctly.

Another cool feature to note: Kotlin has string interpolation so we can directly refer to variables inside a string using $ symbol like println("$first $last")

The above code is quite ugly since we are abusing a list to store and return the result and using the weird slicing syntax to get elements.

We can quickly refactor this code and replace list with a class with 2 properties. With that, we could quite easily use dot to access first name and last name.

Sweet, the code is already cleaner. However if we run this code we observe below output.

Jane Doe
Equals does not work...
Process finished with exit code 0

However we that the two objects are not equal. In Java to make this work we would have to override and create equals(), hashCode()and other convenience methods.

In Kotlin we can directly use data classes which generates the above methods and other convenience functions for us.

data class FullName(val first: String,
val last: String)

If we were to run the same code again this would work just fine.

Functions

1.1 Functions are first class citizens

Kotlin like many modern languages treats functions as a first class citizen. Meaning functions do not need an enclosing class.

Lets understand this with an example.

Below is a simple StringUtils class having some convenience methods to get the first word in a string.

This is similar to how we would write this code in Java. Though this is definitely not idiomatic.

Surely we can do better here.

Turns out we can, Observe the below code for a second. We obviously moved the functions outside the class and removed StringUtils class itself which was obvious but where is the overloaded getFirstWord method?

Turns out Kotlin supports default parameters and so we could always give separator a default value of " " and avoid having to write multiple overloads and the code already looks so much concise.

Obviously i could always pass specific separator value as needed using the named parameter syntax as below:

val first = getFirstWord("Jane,Doe", separator = ",")

1.2 Extension functions

Wouldn’t the above code read so much nicer if we were able to something like below:

"Jane Doe".getFirstWord()

Turns out Kotlin provides a special construct to extend the functionality of a class using functions called extension functions.

All we did is provided the class which we want to extend, in this case String followed by the function name, Since we are working off a string we could remove the word param and instead just refer to the string using this and voila! with this we could achieve our objective and attach new functionality to an existing class which might not be in our control (In this case the Standard String class)

Kotlin also supports extension properties.

How do we do this?

Essentially what we can do is define a new property on String class like val String.lastWord : String and then define a get() which returns us the required value.

val String.lastWord : String

get() {
return this.split("")[1]
}

We can use this just like a normal property with a clean syntax like "John Doe".lastWord

fun main() {
val last = "John Doe".lastWord
println("Last word (Using extension properties) $last")
}

Here is the final code with all the above changes made:

1.3 Inner functions

Kotlin supports local functions without any other ceremony around it. Lets dig into this with an example.

Generally when working with data whether it be in JSON/YAML format we typically might need to use recursion to walk through in the hierarchy.

In the below code:

We have a simple Element base class and a Container class which can wrap multiple Element objects. Also we have a Text class which inherits from Element and holds a text.

If we want to extract texts from all the leaf nodes, then we need to write a function as extractText which takes an element and then either adds it’s text to a StringBuilder object or if it’s a container type then it recurses till it has walked through all elements.

This looks good right? We are using top level functions, however we can improve this code a lot.

If you observe extractFunction()function is only being used inside the extension function on Element so its a good candidate to make it local.

Let’s move it as a local or inner function and also move out StringBuilder and make it a local variable.

Sweet.

We can take this a bit further, We can inline val text = e since we are just assigning the variable to text and using it. Also we can convert this if else statements into a when statement which is more nicer and provides a useful is clause.

Let’s see how it looks like when these refactorings are performed.

This is so much more intuitive than the noisy if else chain of statements.

Can we improve something more on this?

Turns out we can.

for (child in e.children) {
extractText(child)
}

We need to iterate in all elements and then recursively call the function right. This could be very easily replaced with below:

e.children.forEach(::extractText)

The overall function looks like below. We have already made this so much simpler.

However if you see there is an annoying else clause in the when statement. Since we know exactly how many classes inherit from Element, we can improve this by making the Element class as sealed

sealed class Element

And now we can get rid of the else clause since we know that Element subclasses are known

The final code looks like below:

Just by applying idioms of Kotlin language we have been able to reduce the code complexity and increase readability at the same time.

And that’s it for this post.

I would talk about other cool features in a future post as well as how I implemented these in my own api tests. Stay tuned.

If you find this article useful or informative in any way, why not share it with a friend or colleague.

See you all in the 2nd part of this series! Until then, Happy testing and coding! Cheers! ☮️

Comments