Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon

Kotlin Basics

Save for later
  • 7 min read
  • 16 Nov 2016

article-image

In this article by Stephen Samuel and Stefan Bocutiu, the authors of the book Programming Kotlin, it’s time to discover the fundamental building blocks of Kotlin. This article will cover the basic constructs of the language, such as defining variables, control flow syntax, type inference, and smart casting, and its basic types and their hierarchy.

(For more resources related to this topic, see here.)

For those coming from a Java background, this article will also highlight some of the key differences between Kotlin and Java and how Kotlin’s language features are able to exist on the JVM. For those who are not existing Java programmers, then those differences can be safely skipped.

vals and vars

Kotlin has two keywords for declaring variables: val and var. A var is a mutable variable—a variable that can be changed to another value by reassigning it. This is equivalent to declaring a variable in Java.

val name = “kotlin”

Alternatively, the var can be initialized later:

var name: String
name = “kotlin”

Variables defined with var can be reassigned since they are mutable:

var name = “kotlin”
name = “more kotlin”

The val keyword is used to declare a read-only variable. This is equivalent to declaring a final variable in Java. A val must be initialized when created since it cannot be changed later:

val name = “kotlin”

A read-only variable does not mean the instance itself is automatically immutable. The instance may still allow its member variables to be changed via functions or properties. But the variable itself cannot change its value or be reassigned to another value.

Type inference

Did you notice in the previous section that the type of the variable was not included when it was initialized? This is different to Java, where the type of the variable must always accompany its declaration.

Even though Kotlin is a strongly typed language, we don’t always need to declare types explicitly. The compiler can attempt to figure out the type of an expression from the information included in the expression. A simple val is an easy case for the compiler because the type is clear from the right-hand side. This mechanism is called type inference. This reduces boilerplate while keeping the type safety we expect of a modern language.

Values and variables are not the only places where type inference can be used. It can also be used in closures where the type of the parameter(s) can be inferred from the function signature. It can also be used in single-line functions, where the return value can be inferred from the expression in the function, as this example demonstrates:

fun plusOne(x: Int) = x + 1

Sometimes, it is helpful to add type inference if the type inferred by the compiler is not exactly what you want:

val explicitType: Number = 12.3

Basic types

One of the big differences between Kotlin and Java is that in Kotlin, everything is an object. If you come from a Java background, then you will already be aware that in Java, there are special primitive types, which are treated differently from objects. They cannot be used as generic types, do not support method/function calls, and cannot be assigned null. An example is the boolean primitive type.

Java introduced wrapper objects to offer a workaround in which primitive types are wrapped in objects so that java.lang. Boolean wraps a boolean in order to smooth over the distinctions. Kotlin removes this necessity entirely from the language by promoting the primitives to full objects.

Whenever possible, the Kotlin compiler will map basic types back to JVM primitives for performance reasons. However, the values must sometimes be boxed, such as when the type is nullable or when it is used in generics.

Two different values that are boxed might not use the same instance, so referential equality is not guaranteed on boxed values.

Numbers

The built-in number types are as follows:

Type

Width

long

64

int

32

short

16

byte

8

double

64

float

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at R$50/month. Cancel anytime

32

To create a number literal, use one of the following forms:

val int = 123
val long = 123456L
val double = 12.34
val float = 12.34F
val hexadecimal = 0xAB
val binary = 0b01010101

You will notice that a long value requires the suffix L and a float, F. The double type is used as the default for floating point numbers, and int for integral numbers. The hexadecimal and binary use the prefixes 0x and 0b respectively.

Kotlin does not support the automatic widening of numbers, so conversion must be invoked explicitly. Each number has a function that will convert the value to one of the other number types:

val int = 123
val long = int.toLong()

val float = 12.34F
val double = float.toDouble()

The full set of methods for conversions between types is as follows:

toByte()

toShort()

toInt()

toLong()

toFloat()

toDouble()

toChar()

Unlike Java, there are no built-in bitwise operators, but named functions instead. This can be invoked like operators (except inverse):

val leftShift = 1 shl 2
val rightShift = 1 shr 2
val unsignedRightShift = 1 ushr 2

val and = 1 and 0x00001111
val or = 1 and 0x00001111
val xor = 1 xor 0x00001111
val inv = 1.inv()

Booleans

Booleans are rather standard and support the usual negation, conjunction and disjunction operations. Conjunction and disjunction are lazily evaluated. So if the left-hand side satisfies the clause, then the right-hand side will not be evaluated:

val x = 1
val y = 2
val z = 2

val isTrue = x < y && x < z
val alsoTrue = x == y || y == z

Chars

Chars represent a single character. Character literals use single quotes, such as a or Z. Chars also support escaping for the following characters: t, b, n, r, , , \, $.

All Unicode characters can be represented using the respective Unicode number, like so: u1234.

Note that the char type is not treated as a number, unlike Java.

Strings

Just as in Java, strings are immutable. String literals can be created using double or triple quotes. Double quotes create an escaped string. In an escaped string, special characters such as newline must be escaped:

val string = “string with n new line”

Triple quotes create a raw string. In a raw string, no escaping is necessarily, and all characters can be included.

val rawString = “““
   raw string is super useful for
   strings that span many lines
   “““

Strings also provide an iterator function, so they can be used in a for loop.

Arrays

In Kotlin, we can create an array using the arrayOf() library function:

val array = arrayOf(1, 2, 3)

Alternatively, we can create an array from an initial size and a function that is used to generate each element:

val perfectSquares = Array(10, { k -> k * k })

Unlike Java, arrays are not treated specially by the language and are regular collection classes. Instances of Array provide an iterator function and a size function as well as a get and set function. The get and set functions are also available through bracket syntax like many C style languages:

val element1 = array[0]
val element2 = array[1]
array[2] = 5

To avoid boxing types that will ultimately be represented as primitives in the JVM, Kotlin provides alternative array classes that are specialized for each of the primitive types. This allows performance-critical code to use arrays as efficiently as they would do in plain Java. The provided classes are ByteArray, CharArray, ShortArray, IntArray, LongArray, BooleanArray, FloatArray, and DoubleArray.

Comments

Comments in Kotlin will come as no surprise to most programmers as they are the same as Java, Javascript, and C, among other languages. Block comments and line comments are supported:

// line comment

/*
 A block comment
 can span many
 lines
*/

Packages

Packages allow us to split code into namespaces. Any file may begin with a package declaration:

package com.packt.myproject

class Foo

fun bar(): String = “bar”

The package name is used to give us the fully-qualified name (FQN) for a class, object, interface, or function. In the previous example, the Foo class has the FQN com.packt.myproject.Foo, and the top-level function bar has the FQN com.packt.myproject.bar.

Summary

In Kotlin, everything is an object in the sense that we can call member functions and properties on any variable. Some types are built in because their implementation is optimized, but to the user, they look like ordinary classes. In this article, we described most of these types: numbers, characters, booleans, and arrays.

Resources for Article:


Further resources on this subject: