- Kotlin: JetBrains’ JVM goodness
- Kotlin Basics I – If you could show me some code, that’d be great
- Kotlin Basics II – If you could show me some code, that’d be great
Continuing from where we left off, this is the second part covering the basic syntax and constructs in Kotlin. In this article we’ll cover:
. Using control structures and conditional expressions
. Laying out the source code: packages (and directories)
Note: Most of these concepts will be repeated in later articles and in much greater detail. The aim here is to take a swing at the Kotlin syntax and touch some common ideas of the language.
- LOOPING – WHILE AND FOR
Looping in Kotlin is probably one feature that is most similar to how it works in Java, in terms of syntax.
Kotlin provides the
do-whileconstructs exactly the same as Java.
It’s pretty straightforward, so let’s not lurk around here and move on to more interesting bits.
Again pretty similar to Java.
foriterates through anything that provides an
iteratorfor instance, implementations in the Java Collections framework. A
forloop over an array is compiled to an index-based loop that does not create an iterator object.
In the function
simpleForLoopwe can see two variations – the first one uses the
inkeyword to traverse one item at a time and the second that iterates through an array/list with an index (array.indices returns an
IntRange, so it’s iteration through a range).
Another way (as seen in the function
indexedValueForLoop) to iterate through an array with an index is via the
withIndexlibrary function that returns an iterable of the data class
- ITERATING OVER RANGES AND IN-CHECK
So far we’ve seen a few variations of the
forloop but not the regular
forwhere we initialize a variable, update its value at each step and exit the loop when the value hits the boundary condition. But what we have seen is the use of
inthat iterates through ranges. Let’s go ahead and formalize the concept of range to replace our regular loop scenario.
Iterating over ranges
A range is a closed or inclusive interval with a start and a end defined using the
..operator. For example:
val topTen = 1..10
Now as you might have observed, we have a couple of variations of range iterations there –
. a basic progression, where we loop over all the values of the integer range,
. iterating over a progression that has a
stepto skip some values.
stepcan be negative or positive. In our next example we iterate over the range in the reverse order using the
downTo()function. In this case a step size of 2 for instance is effectively -2.
A note about the in keyword
As mentioned above, ranges are closed intervals for comparable types. They implement a library interface
ClosedRange. It has two endpoints: start and endInclusive, which are included in the range. The main operation is contains used in the form of
!inoperator can also be used to check whether a range contains a given value or not. Below we can see a few useful ways to use the range check like checking whether a character is a alphabet or integer or upper-case alphabet and so on.
In the function
doesCollectionContain, we can see that range checks work with collections as well and can be used with any class that is a comparable type (like a set of
ifis an expression in Kotlin as opposed to a statement in Java. It returns a value. As a result, it also serves as a ternary operator ([condition] ? [then] : [else]).
ifcan have block branches as well. The last expression in the block is the result or the return value (in case the last line is a statement and not an expression, the return value is
The last expression in each branch returns a
whenconstruct in Kotlin can be used as replacement for multiple if-else expressions or as a drop-in replacement for Java’s
switchconstruct, although it is much more powerful.
The example above is pretty close to a
switchconstruct in Java with one key deviation-
whendoes not need an explicit
breakkeyword for each branch, only the matched branch is executed. Here, we’ve used
whenas a statement in which case it need not be exhaustive i.e., a default branch is not mandatory.
Let’s re-write the function above, this time with a multiline expression body, returning the result of the
if, can have block branches such that the value returned by a block is the last expression.
In the cases so far, we did not need a default branch due to two reasons-
1. we used
whenas a statement rather than an expression, or
2. the branches were exhaustive in the
whenexpression i.e., the compiler could prove that all the cases were covered in the branches.
In general though, if
whenis used as an expression the default branch is mandatory. For instance if we were to remove the
LinuxDist.MANJARObranch from the example above, we’d end up getting an error- ‘when’ expression must be exhaustive, add necessary ‘MANJARO’ branch or ‘else’ branch instead. The keyword used to specify the default branch is
else. Let’s add one.
No-args when expression
Unlike our examples so far,
whencan be used without passing an argument. This allows the use of arbitrary expressions in the branches and as a replacement for
if-else ifchain, for example:
The branch conditions in this case are simple
Packages (and directories)
At a high level, the concept of packages in Kotlin works the same way as that of Java-
. Source files begin with a
package statement; all classes, functions and properties declared in the file belong to that package
. Declarations can be imported from other files using the
The similarity with Java ends there. Functions (top-level) in Kotlin can be imported much the same way as classes, there’s no distinction (unlike methods in Java).
The actual layout of the files on the filesystem does not have any bearing on the package name. A file may have several classes and functions and it can be named anything. For instance consider the file person.kt (in the image) below.
Notice how the file works as a module and is duly converted into Java compliant package layout when compiled. While this is a flexibility (to each his own), it’s advisable to use conventional package layouts as far as possible (esp. for Java interop).
This culminates the second part of the coverage on basic syntax and constructs. We’ve covered enough for you guys to start writing some useful Kotlin code. I suggest you to attempt the Kotlin Koans as a learning exercise and check out the reference on Kotlin’s official website.
In the next article, we’ll look into the basic types with a special focus on null safety.