An introduction to Kotlin
At at Google I/O 2017, Kotlin was thrown into the spotlight. The language would be given first class support in the android ecosystem. At the time, Kotlin was only “released” for just over a single year. Since this announcement, Kotlin has become the defacto language for developing on Android.
More recently, Kotlin is making moves into new areas such as native desktop applications, web applications (front-end and back-end) and soon, the Apple ecosystem.
Kotlin isn’t just for android
More than ever, Kotlin is being adopted as a language. A 2021 statistica survey of over 31,000 participants found that 14% had used Kotlin in the last 12 months and 9% had plans to adopt/migrate to Kotlin. That is up 100% over a year when compared to a similar survey a year earlier.
As a language that found its first “big break” within the Android ecosystem, Kotlin has been spreading its wings. JetBrains’ dev ecosystem survey shows that 52% of developers are working on web backend while, as expected, 63% are developing for Android.
In the years to come, Kotlin’s mutliplatform programming could swing the balance yet again, as developers will be able to develop native applications for Linux, Mac OS, Windows, IOS, Android and the web all with a common codebase.
Kotlin is maturing
Kotlin is still a young language and this trend continues with the age of developers that use Kotlin. The Koltin census from 2020 noted that 47% of developers were under the age of 30. Of these developers, 40% now have 2+ years of experience with Kotlin.
It is becoming much easier to call yourself “A Kotlin dev” when taking a look at the job market. In fact, Kotlin is now considered to be the 18th most used/interacted with languages over both Github and Stack Overflow. Still a large distance behind the likes of Java, Kotlin is slowly gaining traction as more developers jump into the ecosystem. Even though Kotlin is behind Java, the interoperability means that Java libraries are fully functional in Kotlin!
Language features
Coming from a Java or C# background, a developer will be somewhat familiar with and be able to get started relatively quickly with Kotlin.
The following section will briefly address some of the language features that might be unfamiliar. If not unfamiliar, hopefully these features are interesting and a reason for you try kotlin yourself.
Immutability
Immutability is achieved in many ways in Kotlin. The increased immutability reduces magic (unexpected mutations) and forces developers to opt-in to the more dangerous and potentially harmful world of mutable data.
val and var
Kotlin introduces val and var. You might be able to guess what these mean at a glance.
val: an immutable/read-only local variable
var: a mutable local variable
What is great about val and var is that both of these keywords are the same in length. This means it is super easy to scan through your variables.
Immutable by default
When working with Kotlin, immutability is the default behaviour. When you create a list listOf("a", "b", "c")
, we are creating an immutable list. If you so desire to create a mutable list, you must opt-in.
The same list would look like mutableListOf("a", "b", "c")
when made in a mutable way.
Data class
Java is soon to adopt this language feature. The data class prevents the need for boilerplate and IDE auto-code-generation.
A data class gives you getters and setters (should your variables be var
) along with the usual toString()
, hashCode()
, equals()
and copy()
.
copy()
is not a regular method found in a Java object. This is another move towards immutability. Using this method, we can create a new object keeping some fields, while changing others.
1 |
|
Default values and named parameters
Have you ever had a class with multiple constructors that take a different selection of fields?
With Kotlin and default parameter values, this becomes something of the past. We can set backup values for parameters not passed into a function or constructor. You can also pick and choose what parameters to pass using named parameters.
1 |
|
Null safety
Kotlin tries to eliminate the NPE (in most cases).
We can still use nullable values, however, we are able to work with these values in a safe way.
1 |
|
The type system will not allow you to set a non nullable type (types not denoted with a ?
) to null and will throw a compilation error.
Using a ?
, we are able to work on and chain function calls onto nullable data.
1 |
|
Should you have a nullable piece of data, you can default this to a value of your choice using the “Elvis operator”, named after the king of rock and roll himself.
hint: turn the operator on its side
1 |
|
anotherString
would be set to “fallback” and will be non nullable in type. From now on, the type system will know that this variable is of type String
thanks to smart casting.
Smart casting
Casting values explicitly can be cumbersome and wordy. In kotlin, type checking and casting is done in one step. The casting is kept over the local context of an operation (so long as the compiler can ensure a value’s type will never be mutated).
We introduce the is
keyword here which, as I am sure you will be able to guess, is a type check operator.
1 |
|
We can also use a kotlin when
block, using the following pattern, to work over many different possible types of some x
.
1 |
|
Explicit casting is still possible using the as
keyword. This is usually an unsafe operation and is therefore a smell. However, this can be useful in situations such as unit testing.
Operator overloads
Have you ever wanted your objects to have symbolic methods like +
, -
, *
, /
or other common operators?
With operator overloads any class in kotlin may use these operators. We do not need to have functions called .add()
etc. To do this, we use the Kotlin keyword operator
when writing out our functions, along with a pre-defined naming convention for the function name.
1 |
|
Checked exceptions
Maybe one of the most hated features of Java, checked exceptions have been slowly phased out in the new Java APIs such as Java 8 streams. You can read my articles on the result pattern. These articles go into more detail about the negatives of checked exceptions and the options available to you as a kotlin developer.
Kotlin has done away from checked exceptions and instead, you can throw and catch at any time within the language. You can still interface with Java (either calling Java from Kotlin or Kotlin from Java) should you need to.
Kotlin-Java and Java-Kotlin interop
As mentioned a few times already, Kotlin works amazingly well within a Java code base. Thanks to its bidirectional interoperability, you can migrate from Java to Kotlin file-by-file, class-by-class. This also means that all of the greatest (and worst) Java libraries can be used within a Kotlin only project!
If you want to make sure your code is callable within Java, there are some annotations you can supply such that your code will compile down with the needed metadata required. Head over to the docs to find out more.
Coroutines
You can think of coroutines as lightweight threading. Each coroutine is a suspendable computation that can run on any thread, suspend and then resume on any thread. A coroutine is not tied to a specific thread.
With Kotlin’s coroutines, you can (although it is not advisable to do so) create hundreds of thousands of coroutines. In Java, you would simply run out of memory trying to concurrently spin up this many threads.
Along with this “lightweight threading” comes many extra benefits. Structured concurrency, channels and multiple styles of writing asynchronous computation. The topic is far too large to explain in a small highlight section, so you should check out the documentation if you are interested in learning more. There is a great introduction to coroutines guide that will show you a good number of concepts.
Extension functions
Have you ever had an external class do almost everything you wanted? That little bit of extra functionality that you desire doesn’t need to be placed in some wrapper object. In Kotlin, you can extend functionality of an class using extension functions.
1 |
|