Hey everyone, hope you had an amazing Christmas and an awesome new year’s eve. Welcome to article number 3 of the series and the first one of 2018. In the previous article we went through some of the Kotlin Base Syntax, today is part II of the syntax mini-series, and we’ll look into a few more examples of Kotlin syntax in action.
To recap, in the previous article we talked about Classes, Functions, Variables, Nullability and about the poor semi-colon operator almost not being needed anymore.
Today we’ll start by looking into conditional expressions. If you remember the section about Functions, we saw that functions can work as expressions in Kotlin. Well, the same thing is true for conditional expressions, let’s see:
fun biggestWord(someWord: String, anotherWord: String): String {
if (someWord.length > anotherWord.length) {
return someWord
} else {
return anotherWord
}
}
If we want a function that returns the biggest of 2 Strings, it would look something like the above. But because if
conditions can be used as expressions we can make that code better:
fun biggestWordOneLine(someWord: String, anotherWord: String): String {
return if (someWord.length > anotherWord.length) someWord else anotherWord
}
Much cleaner right? With Koltin we can just return the if
expression straight away, no need for all if
and else
with curly braces in multiple lines.
fun biggestWordAsExpression(someWord: String, anotherWord: String) =
if (someWord.length > anotherWord.length) someWord else anotherWord
But as we saw, functions also work as expressions so we can drop the function curly braces and the return
keyword as well leaving us with the code above. Even cleaner.
Another big change in syntax when switching from Java to Kotlin is the end of the switch
statement. This was replaced with when
in Kotlin and as with the if
statement it can also be used as an expression.
Similar to the switch
statement, every case is evaluated sequentially until one of the conditions is satisfied, and if none is, then the else
case is returned. Looking at the example below if we pass 1 into the when
it will return "One"
only and not "Not a String"
that is actually true as well.
If we use when
as a statement it works the same way as the switch
statement, if we use it as an expression the result is the value of the satisfied case. Let’s see the below code example from the official Kotlin documentation:
fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
As we can see, we’re using when
directly as an expression of a function. As opposed to the switch
statement that has some limitations regarding supported types, with when
we can pass any type and we can even pass the type Any
that corresponds to the Object
type in Java.
And because the type is Any
we can try and evaluate every case by simply testing the values with no casts at all. And look how easy is to do instance of
in Kotlin, an is
it’s all we need.
One important thing to note is that the else
branch is not always mandatory. If you’re using when
as a statement you don’t need to use it, and if you’re using it as an expression you only need to use it if you don’t cover all possible cases.
I would say that a good practice is to always use it anyway. The code is more readable and it’s protected for unexpected values that can come into your function.
Another good example where when
is nice to use, is to replace a if-else-if
chain:
var number = 234
// traditional if-else-if chain
if (number > 0) {
print("number is bigger than 0")
} else if (number < 0) {
print("number is lower than 0")
} else {
print("number is 0")
}
// using when to replace the above chain
when {
number > 0 -> print("number is bigger than 0")
number < 0 -> print("number is lower than 0")
else -> print("number is 0")
}
So, looking at the code above we can see a traditional if-else-if
chain that we would use in Java and then below the version using when
that I personally think looks much better. By passing no parameters to the when
expression, every branch conditions is treated as a boolean expression, so the branch that returns true is executed.
If you try and write the if-else-if
chain as above, Android Studio will actually suggest you to convert the code to use when
instead.
A cool feature that Kotlin also has are range expressions. Ranges basically represent simple closed intervals and can be used with any comparable type, but its implementation is optimised when used with integral primitives types. There are some nice operations we can do with ranges
let’s see some of them:
fun simpleRange(number: Number) {
if (number in 1..100)
print(number)
}
fun simpleRangeReverseWrong() {
for (number in 100..1)
print(number) // this doesn't print anything
}
fun simpleRangeReverseCorrect() {
for (number in 100 downTo 1)
print(number)
}
Cool, so if we want to print a number if it’s between 1 and 100 we can use the in
and ..
operators. If we wanted the opposite we could use !in
and it would print the number if this was not in the 1 to 100 range. These are probably the 3 main operators when working with ranges
but it doesn’t cover everything.
Another simple example is if we wanted to print all numbers from 100 to 1. If we use the ..
operator we don’t get any compilation error but we also don’t get anything printed as the way the ..
operator works is by using a contains
function within a start
and endInclusive
endpoints.
So if we want to print the numbers from 100 to 1 we need to use the downTo
operators that allows us to run through the range in reverse order.
fun until() {
for (i in 1 until 100) {
println(i)
}
}
fun steps() {
for (i in 1..100 step 2) {
println(i)
}
for (i in 100 downTo 1 step 5) {
println(i)
}
}
We can also print all numbers from 1 to 99 if we use the until
operator. It’s similar to ..
but it excludes the last number on the range leaving the 100 out.
And what if we want to print all the odd numbers from 1 to 100 or all 5 multiples from 100 to 1? Easy, we can use the step
operator. It’s basically the same as what we do with the last section of a for
statement in Java. If we don’t use step
it’s the same as using i++
and if we use step 2
for example, it’s the same as using i+2
. As we can see above, step
can be used both with the ..
and the downTo
operators.
We saw an example above while looking at the when
expression, of a couple of type checks examples with the is
and !is
operators. As explained above, those replace the use of instance of
we have in Java.
But the big thing about casting in Kotlin are smart casts. Most of the times we don’t need to explicitly use cast operators as the compiler tracks the outcome of the is
checks and automatically inserts the casts automatically. Let’s see some examples:
fun simple(value: Any) {
if (value is Int) {
print(value == 0) // value is automatically cast to Int
}
}
fun withReturn(value: Any) {
if (value !is Int) return
print(value == 0) // value is automatically cast to Int
}
fun withOr(value: Any) {
// value is automatically cast to Int on the right-hand side of `||`
if (value !is Int || value == 0) return
}
fun withAnd(value: Any) {
// value is automatically cast to Int on the right-hand side of `&&`
if (value is Int && value > 1) {
print(value > 1) // value is automatically cast to Int
}
}
As we can see in the first example, we’re using is
to check if the value is of type Int
and then we can straight away print the result of the expression value == 0
without casting value to Int, as Kotlin does it for us automatically, neat right?
Even better it works in the opposite case as well.On the second example, we just return if value
is not of Int
type or continue if it is. Again, because the code reached the print statement Kotlin already knows that value
is an Int
so it automatically casts it for us and no need to do a Java like (Int) value
explicit cast.
Wait for it, it also works with ||
and &&
expressions as we can see in the bottom 2 examples. Kotlin automatically casts value
on the right-hand side of the expression based on the result of the left-hand side. And in the last example, again we can see the automatic cast in action in the print function.
This is a very cool Kotlin feature that will save us a lot of boilerplate code we need in Java whenever we’re casting stuff. No more hurting our eyes with a load of ()
all over the place.
And that’s it for now if you enjoyed the article don’t forget 👏 and please share your ideas and comments. The code used for this article is also under the syntax
package. Series Github project link below. See you at number 4 👋
Kotlin Syntax Part I — why am I excluded? ⇦ PREVIOUS
NEXT ⇨ Kotlin data classes — enough boilerplate