Kotlin Basics II – If you could show me some code, that’d be great

  This entry is part 3 of 3 in the series Learn me some Kotlin

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.

Control Flow

    Looping in Kotlin is probably one feature that is most similar to how it works in Java, in terms of syntax.

    Kotlin provides the while and do-while constructs exactly the same as Java.

    It’s pretty straightforward, so let’s not lurk around here and move on to more interesting bits.
    Refer: https://kotlinlang.org/docs/reference/control-flow.html#while-loops

    Again pretty similar to Java. for iterates through anything that provides an iterator for instance, implementations in the Java Collections framework. A for loop over an array is compiled to an index-based loop that does not create an iterator object.

    In the function simpleForLoop we can see two variations – the first one uses the in keyword 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 withIndex library function that returns an iterable of the data class IndexedValue.
    Refer: https://kotlinlang.org/docs/reference/control-flow.html#for-loops

    So far we’ve seen a few variations of the for loop but not the regular for where 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 in that 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 step to skip some values.

    The step can 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.

    Refer: https://kotlinlang.org/docs/reference/ranges.html#ranges

    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 in/!in operator.

    The in/!in operator 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 String values.

    if is 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]).

    if can 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 Unit).

    The last expression in each branch returns a Boolean value.
    Refer: https://kotlinlang.org/docs/reference/control-flow.html#if-expression

    The when construct in Kotlin can be used as replacement for multiple if-else expressions or as a drop-in replacement for Java’s switch construct, although it is much more powerful.

    The example above is pretty close to a switch construct in Java with one key deviation- when does not need an explicit break keyword for each branch, only the matched branch is executed. Here, we’ve used when as 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 when expression directly.

    Note: A when expression, like 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 when as a statement rather than an expression, or
    2. the branches were exhaustive in the when expression i.e., the compiler could prove that all the cases were covered in the branches.

    In general though, if when is used as an expression the default branch is mandatory. For instance if we were to remove the LinuxDist.MANJARO branch 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, when can be used without passing an argument. This allows the use of arbitrary expressions in the branches and as a replacement for if-else if chain, for example:

    The branch conditions in this case are simple Boolean expressions.

    Refer: https://kotlinlang.org/docs/reference/control-flow.html#when-expression

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 import statement

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.

Kotlin source code layout - Packages

Kotlin source code layout – Packages

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.

Series Navigation<< Kotlin Basics I – If you could show me some code, that’d be great

Leave a Reply