In the previous post I briefly introduced Kotlin's syntax, always contrasting with JavaScript snippets. But again, there are a few places where Kotlin have unique approaches that draw no parallel with JS (and many other languages, for what matters). The most prominent example is Kotlin’s approach to nullability — it is pervasive in all Kotlin code, so you have to learn about it if you want to learn Kotlin, but there is really no direct parallel in JavaScript. Another example is Asynchronous programming, which kind of does have a parallel with JavaScript Promises and Async/Await, but with much more options and control over execution models and threads.
Nullability
Javascript has two “non-values” — undefined and null. The former is used by the language to inform the absence of a value and the latter can be used by the developer to explicitly set something to a non-existent value — but more often than not they cause more trouble than they solve. How many times have you dealt with “Uncaught TypeError: Cannot read property x of undefined” or “TypeError: ‘null’ is not an object”?
The whole concept of null references was considered by its own inventor, Tony Hoare, the billion dollar mistake. He also said that “Programming languages should be responsible for their users” — and many modern programming languages provides mechanisms for Null-Safety, but Kotlin’s approach deserves special merits for being pragmatic, simple & elegant.
Kotlin supports nullability as part of its type System — That means You have the ability to declare whether a variable can hold a null value or not. Let’s take a look at an example:
var greeting: String = "Hello, World"
greeting = null // Compilation Error
By default, Kotlin assumes that greeting cannot be null:
To allow null values, you have to declare a variable as nullable by appending a question mark in its type declaration:
var nullableGreeting: String? = "Hello, World"
nullableGreeting = null // Works
By supporting nullability in the type system, the compiler tracks your variables and refuses to compile if your null values are not being handled.
For example, The following method access works because Kotlin knows that the variable greeting can never be null:
val len = greeting.length
But the same method call won’t work with nullableGreeting variable -
val len = nullableGreeting.length // Compilation Error
If you handle the possibility of the null value, the Kotlin compiler will happily accept your code without errors:
val len = if (nullableGreeting != null) {
nullableGreeting.length
} else {
0
}
Safe Call operator
Of course, Null Comparisons are a little too verbose. Kotlin provides a Safe call operator, ?.
that combines a null-check and a method call in a single expression.
Let's look at an example:
val a = "Kotlin"
val b: String? = null
println(a?.length) // 6
println(b?.length) // null
That’s great but that’s not all. You can chain multiple safe calls like this:
val currentCity: String? = user?.address?.city
Such a chain returns null if any of the properties in it is null.
Elvis Operator
If you want to provide a default value if some variable is null, you can use the Elvis operator ?:
val name = nullableUserName ?: "Guest"
You can use the safe call operators (or any other expressions) on the left side of Elvis operator:
val name = nullableUser?.name ?: "Guest"
Asynchronous Programming
Asynchronous or non-blocking programming is the new reality: Whether we’re creating server-side, desktop or mobile applications, it’s important that we provide an experience that is not only fluid from the user’s perspective, but scalable when needed.
JavaScript is a Single-threaded language that uses an Event Loop to allow asynchronous behavior: When fetching from a remote server, setting a timer or any other async operations, you provide a callback and the event loop will take care of the task and notify when done. Newer versions of the language provides abstractions on top of that (promises and async/await) that allows the developer to write async code that looks like synchronous code.
Kotlin is a multi-threaded language — the developer can spawn multiple threads and execute code truly concurrently, and the language also has a built-in co-routine mechanism with support for Deferred (analogous to promises) and async/await patterns:
JavaScript
async function getStatus() {
const currentUserPromise = someApi.fetchUser();
const currentCompanyPromise = someApi.fetchCompany();
return await Promise.all([currentUserPromise, currentCompanyPromise]);
}
Kotlin
suspend fun getStatus(): List<String> {
val currentUserDeferred = someApi.fetchUser()
val currentCompanyDeferred = someApi.fetchCompany()
return listOf(currentUserDeferred.await(), currentCompanyDeferred.await())
}
To be fair, this is one very small example of Kotlin’s coroutines and deferrend usage — the language (and its standard lib) provides many, many more options other than suspend, async and await, giving the developer finely grained control over the async execution (including cancelation, thread pools any many other things that doesn't have an equivalent in JavaScript). Again, the objective here is just to get you a broad, birds-eye view of the language. It's nice to be aware that coroutines and deferrends exist and do a technical dive after familiarizing yourself with the language as a whole.
Where to go from here?
The objective of these articles is to be a very brief introduction to Kotlin, just to give you a sense on what the language looks like and give you a head start. There are, of course, a lot of missing information here, but this should be just enough for you to start playing around with the language.
You can play around without installing anything on the Kotlin Playground. If you feel like having a challenge, try the Kotlin Koans.
Top comments (3)
Love this! Thank you!
Thanks, Cássio! Great article!
Thank you very much for the article!