Kotlin in Action Summary - Part 1
Tags: kotlin, android, programming
Published: 2022-08-09 08:37:00

In this series, we will explore the most important topics in the [Kotlin in Action](https://www.amazon.com/Kotlin-Action-Dmitry-Jemerov/dp/1617293296) book. Because this is just a summary of the book without the details, and to get the most of this series, I highly recommend that you read the book and after reading each chapter, you can read the corresponding article to review the concepts and material. This series is also great for developers who are getting ready for an interview. Because chapter 1 of the book is just some general information, we will skip this chapter and start from chapter 2 of the book. I will mention the page number after each section title, so you will be able to read the concept if it is not clear by the article. Let's dive in.

If you have already read this article or you feel you do not need to read this chapter, you can read part 2 [here](https://dev.to/abolfazlimahdi/kotlin-in-action-summary-part-2-j68).

## Functions
#####pages 18, 19
![Declaring a Function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ntg91pfefjxw3mi94fm.png)
1. To declare a function, we use the **fun** keyword.
2. Functions can be declared at the top level of the file(outside the class).
3. Parameter types are written after the parameter name separated by a colon.
4. Return type of the function is written after the parameters' parentheses separated by a colon.
5. If function is a block expression, we can omit the return type and the curly braces(block expression is discussed later).

## Statements vs Expressions 
#####page 19
An expression has a value which can be used as a part of another expression.
A statement is a top-level element in its enclosing block and does not have its own value. 
Most of Java statements can be used as expressions in Kotlin(if, try, when). Because if can be used as an expression in Kotlin, we do not have ternary operator(int k = booleanVariable ? 1 : 0;) that Java has.
Please bear in mind that if can be either used as an expression or statement in Kotlin. If it covers all the cases and assigned to a variable, it is an expression. Otherwise, it is a statement.

## Expression Body vs Block Body
#####page 19
If a function returns a value directly without using the curly braces, it has an *expression body*. On the other hand, if the function has the curly braces, it has a *block body*.

## Variables
#####pages 20, 21
Unlike Java, Kotlin does not require us to begin variable with their type because there are times we can omit the variable type(using the type inference capability of the Kotlin compiler). 
We use **val** or **var** to declare variables in Kotlin. val is the shorthand for value and var is the shorthand for variable. As the names suggest, val is immutable and var is mutable.
**NOTE:** We should always use the val keyword and use the var if we really need to change the variable, then we should use the var.
**NOTE:** Although val creates an immutable variable, bear in mind that the object itself might be mutable.

```kotlin
val s = arrayListOf("hi")
s.add("hello")
```
## String Templates
#####page 22
Kotlin supports String templates. We can declare a variable, then use it alongside with the dollar sign($) to mention it in strings.

```kotlin
val appleNumbers = 1100
println("there are $appleNumbers in the inventory")
```
**NOTE:** If we want to use the dollar sign itself in a string, we should escape it:
```kotlin
println("\$x")
```
This will print $x, not the value of a variable named x.

## Classes and Properties
#####pages 23, 24, 25
```kotlin
class Person {
    val name: String,
    var isMarried: Boolean
```
Classes that contain only data and no other code are called value objects.

In Kotlin, public is the default visibility modifier.

In Java, the combination of a field and its accessors is often referred to as a property. In Kotlin, properties are supported by the language and replace fields and accessor methods.
When we declare a property as val, a field and a getter is generated for them. Whereas for the var properties, a field, a getter and a setter is generated.

When we call the property of an object, it seems like we are accessing it directly, but under the hood, we are accessing it via the getter method generated.
`val person = Person("Bob", true)`
`println(person.name)`
Bob
`>>>print(person.isMarried)`
true

There are cases when we do not need a backing field for a property. For example, if we can calculate the property from the value of other properties. We can declare a custom getter for such a property, and no backing field will be generated for that.
```kotlin
class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() {
            return height == width
        }
}
```
In the code above, the compiler will not generate any backing field for the *isSquare* property.

## Enums
#####pages 28, 29
```kotlin
enum class Color {
    RED, BLUE, YELLOW, GREEN
}
```
Enum is a rare case in Kotlin that uses more keywords than the Java's equivalent. 

In Kotlin, enum is a soft keyword. It has a special meaning when it comes before class, but we can use it elsewhere in our code.

Enums are not just a list of values. We can declare methods and properties in enums.
```kotlin
enum class Color(
  val r: Int, val g: Int, val b: Int
) {
  RED(255, 0, 0), BLUE(0, 0, 255), YELLOW(255, 255, 0), 
    GREEN(0, 255, 0);

  fun rgb() = (r * 256 + g) * 256 + b
}
```
1. In the enum constructor, we have declared the properties of enum constants.
2. Semicolon is required if we declare methods in the enum.

## When
#####pages 29, 30, 31
Like *if*, *when* is an expression that returns a value.
Unlike Java, *when* does not require us to write *break* after each case.
```kotlin
fun getWarmth(color: Color) =
  when (color) {
    Color.RED -> "warm"
    Color.BLUE -> "cold"
    Color.YELLOW -> "warm"
    Color.GREEN -> "neutral"
  }
    
```
We can combine multiple values in the same branch separated with a coma(,).
```kotlin
fun getWarmth(color: Color) =
  when (color) {
    Color.RED, Color.YELLOW -> "warm"
    Color.BLUE -> "cold"
    Color.GREEN -> "neutral"
  }
    
```

Unlike *switch* in Java which requires us to use constants(enums, strings, or number literals) as branch conditions, *when* in Kotlin allows us to use any objects.
```kotlin
fun mix(c1: Color, c2: Color) =
  when(setOf(c1, c2)) {
    setOf(RED, YELLOW) -> ORANGE
    setOf(BLUE, YELLOW) -> GREEN
    setOf(BLUE, VIOLET) -> INDIGO
    else -> throw Exception("Dirty color")
  }
}
```
Here we have used *Set* as the branch condition.

The previous example is not efficient because it creates a set for every invocation. We can instead use a *when* without an argument to accomplish the same result:
```kotlin
fun mixOptimized(c1: Color, c2: Color) =
  when {
    (c1 == RED && c2 = YELLOW) || 
    (c1 == YELLOW && c2 = RED)  -> ORANGE
    
    (c1 == BLUE && c2 = YELLOW) || 
    (c1 == YELLOW && c2 = BLUE) -> GREEN
  
    (c1 == BLUE && c2 = VIOLET) || 
    (c1 == VIOLET && c2 = BLUE) -> GREEN -> INDIGO
    else -> throw Exception("Dirty color")
  }
}
```
**NOTE:** If no argument is supplied for the *when* expression, the branch condition is any boolean expression.

## Smart Casts
#####pages 31, 32, 33
To illustrate the casting mechanism in Kotlin, we will use an example in arithmetic expression. In this example, we will just use one operation: the sum of two numbers. Let's dive in:
First we declare an interface to have the same type for both a value and an expression of two values. Then, we implement the interface in two classes *Sum* and *Num*.

```kotlin
interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
```

**NOTE:** To implement an interface in a class, we use a colon after the class name, and then the interface name:

The *Expr* interface has two implementations, so we have two options:
1. If an expression is a number, we return the corresponding value.
2. If it's a sum, we have to evaluate the left and right expressions and return their sum.

First, let's see a simple implementation:
```kotlin
fun eval(e: Expr) : Int {
  if (e is Num) {
    val n = e as Num
    return n.value
  }
  if (e is Sum) {
    return eval(e.right) + eval(e.left)
  }
  throw IllegalArgumentException("unknown expression")
}
```
**is vs instanceof**
The *is* check in Kotlin is the same as the instanceof in Java. In Java, if we have checked a variable with the *instanceof*, we also have to cast it to the type. However in Kotlin, if we check a variable with the *is* check, it already can be used as the type we have checked with the *is* check. In effect, the compiler performs the cast for us(which is called **smart cast**).

**NOTE:** The smart cast works only if a variable could not have changed after the *is* check. For a property of a class, it must be *val* or it should not have a custom accessor!

Because we have the smart cast option in Kotlin, we can remove the cast in the above code.
We can also remove the curly braces and the return keywords, because in Kotlin if is an expression. 
The result of the two above modifications is:
```kotlin
fun eval(e: Expr) =
  if (e is Num) {
    e.value
  } else if (e is Sum) {
    eval(e.right) + eval(e.left)
  } else
  throw IllegalArgumentException("unknown expression")
```
**NOTE:** Both *if* and *when* can have blocks. In this case, the last expression in the block is the result.

We can also replace the if branches with when:
```kotlin
fun eval(e: Expr) =
  when (e)  {
    is Num -> e.value
    is Sum -> eval(e.right) + eval(e.left)
   else -> throw IllegalArgumentException("unknown expression")
  }
```
## The While Loop
#####page 35
The *while* and *do while* loop in Kotlin is the same as their corresponding loops in Java.
```kotlin
while (condition) {
  //while block
}

do {
  //do-while block
} while(condition)
```

## For Loops and Ranges
#####pages 36, 37
Java for loop: We initialize a variable, update its value on every step in the loop, exit the loop when the value reaches a certain bound.
Kotlin introduced *ranges* to replace the common loop use-case.
**Range:** A range is an interval between two values, usually numbers: a start and an end. We write it using the .. operator.
**NOTE:** Ranges in Kotlin are closed or inclusive(the second value is always part of the range).


```kotlin
val oneToTen = 1..10
for (i in oneToTen) {
  println(i)
}

for (i in 1..10) {
  println(i)
}
```
In ranges, we can use *downTo*, *step* and *until* functions. 
**downTo:** iterates backward in a loop
**step:** allows us to skip some numbers
**until:** allows us define a half-closed range(the last value is not included in the range)
```kotlin
for (i in 100 downTo 1 step 2) {
  println(i) //prints 100, 98, 96 ... 4, 2
}

for (i in 1 until 100) {
  println(i) //prints 1, 2, 3, ..., 98, 99
}
```

## Iterating over Collections
#####pages 37, 38
The most common use-case of a *for in* loop is to iterate over a collection. Let's see how we can do this in Kotlin.

At first, we will see how to use the for loop to iterate through a map:
```kotlin
val binaryReps = TreeMap<Char, String>()
//here we will create a range of characters
for (c in 'A'..'F') {
  val binary = Integer.toBinary(c.toInt())
  //put each binary character in the map
  binaryReps[c] = binary
}

//iterating through the map
for ((letter, binary) in binaryReps) {
  println("$letter = $binary")
}
```
In the above code, we can see that the range function not only works for numbers, but also works fine for characters.
We can also see that we are unpacking the elements of a collection to iterate over them. In the case of maps, we should unpack it into two variables: one for the key the other for the value.

**NOTE:** As we can see, we are using the shorthand version of accessing and updating the map values. We use the map[key] = value instead of using the get and put functions:
`map[key] = value`

We can also iterate through a collection and keep track of the index of the current item:

```kotlin
val list = arrayListOf("10", "11", "1001")
//here we iterate through each element in the list
for (element in list) {
    println("$element")
}

//here we iterate through each element in the list and keep the index of current element
for ((index, element) in list.withIndex()) {
    println("$index: $element")
}
```

## The *in* operator
#####pages 38, 39
We can use the *in* operator to check whether a value is in a range, or its opposite, *!in*, to check whether a value is NOT in a range:

```kotlin
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'

fun isNotDigit(c: Char) = c !in '0'..'9'
```
The *in* and *!in* operators also work in *when* expressions:

```kotlin
fun recognize(c: Char) = when (c) {
    in '0'..'9' -> "It's a digit!"
    in 'a'..'z' , in 'A'..'Z' -> "It's a letter!"
    else -> "I don't know!"
}
```
**NOTE:** Ranges are not restricted to the characters either. If you have any class that supports comparing instances (by implementing the _java.lang.Comparable_ interface), you can create ranges of objects of that type. But keep in mind that you cannot enumerate all objects in the range.


## Exceptions
#####pages 39, 40
Exception handling Kotlin is similar to Java. A function can complete in a normal way, or throw an exception. Either the caller catches and handles the exception, or the exception propagates and is rethrown further up the stack.
Unlike Java, in Kotlin the _throw_ construct is an expression and can be used as a part of other expressions:

```kotlin
val percentage =
    if (number in 0..100)
        number
    else
        throw java.lang.IllegalArgumentException("Illegal percentage value")
```
## _try_, _catch_, and _finally_
#####pages 40, 41
Just like Java, we can use the _try_ with _catch_ and _finally_ blocks.

```kotlin
fun readNumber(reader: BufferedReader): Int? {
    try {
        val line = reader.readLine()
        return Integer.parseInt(line)
    } catch (e: java.lang.NumberFormatException) {
        return null
    } finally {
        reader.close()
    }
}
```
The biggest difference in exception handling between Java and Kotlin is that _throws_ clause is NOT present in the code because Kotlin does not differentiates between checked and unchecked exceptions.

## _try_ as an Expression
#####pages 41, 42
The _try_ keyword in Kotlin, just like _if_ and _when_, introduces an expression, and you can assign it to a variable. Unlike if, you have to enclose the try statement body in curly braces.

```kotlin
fun readNumber(reader: BufferedReader) {
    val number = try {
        val line = reader.readLine()
        Integer.parseInt(line)
    } catch (e: java.lang.NumberFormatException) {
        null
    }
}
```
If the execution of a _try_ block behaves normally, the last expression in the block is the result. If an exception is caught, the last expression in a corresponding _catch_ block is the result.


This is the end of part 1 which was the summary of chapter 2.  There were other parts in chapter 2 that I did not cover here because I felt they are not as important and they would have made the article too long. Anyhow, if you found this article useful, please like it and share it with other fellow developers. If you have any questions or suggestions, please feel free to comment. Thanks for your time.

Here is the [link](https://dev.to/abolfazlimahdi/kotlin-in-action-summary-part-2-j68) to part 2 of this series.