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

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

In the previous installment of the series we tried to answer what’s Kotlin all about. Now before we start looking under the bonnet, let’s just take it for a spin a bit.

We’ll go through several code snippets to get a taste of Kotlin and ease into its syntax. In fact, syntax is one of the several things where Kotlin excels – it’s lean and compact.

The article is split into two parts the first of which (this one) covers declaring the basic elements:
. functions,
. variables and
. classes and properties

Note: Before we begin; 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.

Basic elements

This section covers the basic elements that a Kotlin program is composed of- functions, variables and classes (and properties), although as we shall see that a program in Kotlin doesn’t always require a class.

    Kotlin is not a functional programming language but it does accord functions a first-class citizen status (unlike Java that only has methods). It provides just enough support of functional programming constructs that make sense in an otherwise object-oriented language. For instance, it has immutable data classes and supports higher-order functions (functional types) such that they can be passed around as arguments or return types.

    Our first function in Kotlin
    Let’s begin our discussion on functions by declaring a small function celsiusToFahrenheit which does exactly what it says.

    So what all is going on here ?
    . Functions are declared with the fun keyword (we are not using an access specifier which defaults to public, but more on that later)
    . Parameters take the syntax parameter_name: parameter_type
    . Return type is declared after the parameter list (again, preceded by a colon)
    . A class wasn’t required to hold the function since functions can be declared at the top level of a file (including main).

    Block body vs Expression body
    In the example above, the function body is written in the block style, inside curly braces as a set of statements (and expressions) and has an explicit return statement (this is what we are familiar with coming from the Java world). Kotlin provides a way to simplify further with expression style where the body consists of a single expression.

    Notice how we got rid of the return type from the function declaration since the type is now inferred by the compiler by evaluating the expression.

    Unit returning functions
    Some functions do not return any meaningful value. The return type for such functions is Unit which corresponds to void in Java.

    The Unit return type is optional and the two functions above are equivalent.

    Named Arguments
    Consider the function join which accepts a list of Strings to join, along with a separator, a prefix and suffix.

    Is there anything wrong with the first style of invocation (// 1)? Probably not much except that it’s not readable. Unless we jump into the method signature, we cannot answer questions like which one is the separator or prefix or suffix (esp. since the data type is same for all).
    With Kotlin we can improve the readability with named arguments. We can invoke the function explicitly passing the argument names (// 2). Also, we may pass the arguments in any arbitrary order if we pass the argument names along (// 3).
    The real fun with named arguments begins with default parameter values which is coming up next.

    Default Parameter Values
    In Kotlin, we can supply default values for parameters in the function declaration. Let’s revisit our join function and add some default values.

    Now when we invoke the function, we can omit any (or all) of the parameters with default values (// 1 and // 2). Notice that we could skip the trailing arguments without the use of named parameters; but if we do, we can omit arbitrary arguments in the list, specifying just the ones that are needed (// 3).
    Coming from a Java background this can often avoid the explosion of overloaded methods in some classes. With default parameters, we have a way to enable multiple ways of invoking a function.

    The variable declaration doesn’t begin with a type (type inference, remember ?). Kotlin provides two keywords that identify a variable declaration, based on mutability:
    var refers to a mutable reference; corresponds to a regular Java variable. The value of such a variable can be changed.

    val refers to an immutable reference; corresponds to a final Java variable. Such a variable cannot be reassigned (dare not try ;)).

    Type Inference
    The type declaration can be omitted if the compiler can infer the type.

    Nullable variables
    Variables in Kotlin cannot be null by default. They can be made nullable by adding a ? to the type declaration.

    This explicit support for nullability helps the compiler to prohibit inadvertently calling methods on values that may be null at run-time, hence preventing NullPointerException errors.

    Uninitialized variables
    In case the variables are uninitialized at the time of declaration, the type needs to be specified.

    The concepts in this section are not really new and bear a lot of resemblance to how classes are used in Java. At the same time, Kotlin has significant differences that reduce a lot of boilerplate and make it convenient to work with classes.

    Let’s start off easy with a simple class, not having any fields. It just has a member function and an implicit no parameters default constructor.

    Let’s look at another class but with parameters this time. We have a Book with a couple of parameters title and author of type String. Such classes with data but no business logic are pretty common in the codebase and are used as entities/VOs/DTOs.

    Isn’t that just easy on the eyes? Kotlin adds an implicit constructor.

    Primary constructor
    The code in the parenthesis with the parameters is the implicit constructor and is called the primary constructor. If we were to look under the covers, this is what it looks like:

    The constructor keyword is optional and is just for illustration. In addition there is an init or the initializer block that is executed when the primary constructor is used at the time of creation of an instance of the class (the initializer can be customized beyond the trivial case here).

    Default constructor arguments
    Much like the default parameter values for functions, default arguments can declared for constructors. The optional arguments can be omitted.

    In all of our examples above, notice how we create an instance. It resembles calling a function and does not require the new keyword.

    In a typical Java class we have fields along with their getters and (maybe) setters that together are referred to as properties. Kotlin keeps properties as a first-class feature with implicit accessor/mutator methods. Of course, they address the trivial case but end up eliminating a lot of boilerplate compared to Java. So by simply declaring a property, we declare their accessors as well. Let’s look back at the Book class.

    Notice that the properties can be mutable or immutable like variables (var vs. val). In case of a immutable property only the getter is generated while both getter and setter is generated for a mutable property.

    Custom accessors
    Beyond the trivial case we can define custom implementations. Let’s take an example of the class User below. The class has three properties- firstName, lastName and _email.

    While firstName and lastName are trivial, we need a custom implementation for _email that validates if it’s a valid email address before setting the value. The property email (without the underscore) doesn’t having a backing field of its own to store the value but is used to provide custom getter and setter for _email.
    Also, we have a fullName property which concatenates the first and last names on the fly- again it does not have a backing field but computes the value every time the property fullName is accessed.

    The properties are by default public and are accessed by their names as shown above. The visibility modifier is a topic with its own discussion which we’ll get to in a later article, soon.

That’s all for this installment. We’ll continue discussing the basic syntax in the next one focusing on control flow structures and a couple of miscellaneous topics.

Series Navigation<< Kotlin: JetBrains’ JVM goodnessKotlin Basics II – If you could show me some code, that’d be great >>

Leave a Reply