- 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
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:
. 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.
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
celsiusToFahrenheitwhich does exactly what it says.
So what all is going on here ?
. Functions are declared with the
funkeyword (we are not using an access specifier which defaults to
public, but more on that later)
. Parameters take the syntax
. 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
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
Unitwhich corresponds to
Unitreturn type is optional and the two functions above are equivalent.
Consider the function
joinwhich 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
joinfunction 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:
varrefers to a mutable reference; corresponds to a regular Java variable. The value of such a variable can be changed.
valrefers to an immutable reference; corresponds to a
finalJava variable. Such a variable cannot be reassigned (dare not try ;)).
The type declaration can be omitted if the compiler can infer the type.
Variables in Kotlin cannot be
nullby 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
nullat run-time, hence preventing
In case the variables are uninitialized at the time of declaration, the type needs to be specified.
CLASSES AND PROPERTIES
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
Let’s look at another class but with parameters this time. We have a
Bookwith a couple of parameters
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
The code in the parenthesis with the parameters is the implicit
constructorand is called the primary constructor. If we were to look under the covers, this is what it looks like:
constructorkeyword is optional and is just for illustration. In addition there is an
initor 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
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
Notice that the properties can be mutable or immutable like variables (
val). In case of a immutable property only the getter is generated while both getter and setter is generated for a mutable property.
Beyond the trivial case we can define custom implementations. Let’s take an example of the class
Userbelow. The class has three properties-
lastNameare trivial, we need a custom implementation for
_emailthat validates if it’s a valid email address before setting the value. The property
Also, we have a
fullNameproperty 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
The properties are by default
publicand 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.