Kotlin in Action Summary - Part 2
Tags: android, kotlin, programming
Published: 2022-08-14 12:39:00

This is part 2 of the series Kotlin in Action Summary. [Here is the link to part 1](https://dev.to/abolfazlimahdi/kotlin-in-action-summary-part-1-chapter-2-1oie) which we talked about chapter 2 of the book with the title "Kotlin basics". As mentioned before, it is highly recommended to read the book first and consider this series as a refresher. We do NOT cover all the materials in the book. Let's start with part 2, chapter 3 of the book: "Defining and Calling Functions"!

## Creating Collections
Let's see how we create collections in Kotlin:

```kotlin
val set = hashSetOf(1, 7 ,53)
val list = arrayListOf(1, 7, 53)
val map = hashMapOf(1 to "one", 7 to "seven", 53 to "fifty-three")
```
**NOTE:** Note that _to_ in the _hashMapOf_ is a normal function Kotlin. We will cover it later in the section **Infix Calls**.

**NOTE:** Kotlin uses standard Java collections to make it easier to interact with Java.

Java collections have a default _toString_ implementation and the formatting of the output is fixed. If we want to change this formatting, we use third party libraries like Guava or Apache Commons. In Kotlin, a function to handle this issue is part of the standard library.
We use _joinToString_ function to accomplish the mentioned task. This function appends elements of the collection to a _StringBuilder_, with a separator between them, a prefix at the beginning and a postfix at the end:

```kotlin
fun <T> joinToString(
    collection: Collection<T>,
    separator: String,
    prefix: String,
    postfix: String

) : String {
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()) {
        if (index > 0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}
```
We will edit this function to make it less verbose.

## Named Arguments
The first problem with Java's function calls is that if they have a number of arguments especially with the same type (as we have with the _joinToString_ function), the role of each argument is not clear. This is especially problematic with boolean flags. In Java, some programmers use enums as boolean flags and others write comments in the function declaration before each parameter. 
Fortunately, Kotlin has come up with a better solution. We can write the name of each argument and assign a value to that. This makes the code much more readable:

```kotlin
val list = listOf(1, 7, 53)

joinToString(
collection = list, separator = ",", prefix = "(", postfix = ")"
)
```
**NOTE:** If we specify the name of an argument in a call, we must specify the name of all other arguments after that.

**NOTE:** Unfortunately, we can't use name arguments when calling methods from Java.

## Default Parameter Values
One of the problems with Java functions is the huge number of overloaded methods. Programmers provide overloaded methods for several reasons: backward compatibility, convenience of API users or other reasons. Most of the times, we have a method with all the parameters and other overloaded methods are just a simpler version of that method that omitted some of the parameters and provided them with default values.
In Kotlin, we can avoid overloaded methods because we can provide default parameter values:

```kotlin
fun <T> joinToString(
    collection: Collection<T>,
    separator: String = ", ",
    prefix: String = "",
    postfix: String = ""

): String {
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()) {
        if (index > 0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}

val list = listOf(1, 7, 53)

joinToString(
collection = list, prefix = "(", postfix = ")"
)
joinToString(
collection = list, separator = "- "
)
```
Here, we have provided default values for `separator`, `prefix` and `postfix`. So, we can omit them in some calls or provide all of them. If we wanted to have exact the same functionality in Java, we should have provided 8 overloaded methods.

**NOTE:** When we are using normal function calls, we should keep the ordering of the arguments the same as the parameters in the function and you can only omit the trailing arguments. But with name arguments, we can provide arguments at any order and we can omit any argument with default values anywhere in the function.

**NOTE:** Default values are encoded in the function being called, not at the call site.

## Default Values and Java
When we want to use default values from Java code, we should use the @JvmOverloads annotation on the function. This annotation will tell the Kotlin compiler to provide the Java overloaded functions we need to call from Java.

## Top-Level Functions and Properties
Unlike Java, Kotlin does not require us to write all functions and properties in classes. This is specially useful because we can avoid create Utility classes. We can write functions at the top-level of a source file, outside of any class. Such functions are still a part of the package they are declared in and we should import them to use them in other packages.

```kotlin
package strings

fun joinToString(...) : String { ... }
```
How is this compiled and how does it run? Top-level functions and properties are compiled to static methods and static members of a class. Which class? The compiler will create a class called `FileNamekt.java` and when we want to call these functions from Java, we should use `filename.theFunction()`.
Why does this happen? Because JVM can only execute codes in a class.
Let's assume the above code is in `join.kt` file. Here's how we can use it in our Java code:

```java
import strings.JoinKt

public class MyClass {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("one", "two", "three");
        JoinKt.joinToString(list, ", ", "", "")
    }
}
```
**NOTE:** To change the class name that contains top-level functions generated by the Kotlin compiler, we can use the `@file:JvmName("MyPreferredFileName")` annotation. We must put this annotation at beginning of the file, even before the package name.
Here we can see a Kotlin file with top-level functions named `Join.Kt`:

```kotlin
@file:JvmName("StringFunctions")

package strings

fun <T> joinToString(
    collection: Collection<T>,
    separator: String = ", ",
    prefix: String = "",
    postfix: String = ""

): String {
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()) {
        if (index > 0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}
```
Java class that calls the new name of the Kotlin top-level functions:

```java
import strings.StringFunctions

public class MyClass {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("one", "two", "three");
        //notice that we changed the class name with @file:JvmName annotation
        StringFunctions.joinToString(list, ", ", "", "");
    }
}
```

## Top-Level Properties
Properties can also be placed at the top level of a file. The value of such a property is stored in a static field.
Top-level properties can be used to define constatns:

```kotlin
val UNIX_LINE_SEPARATOR = "\n"
```
**NOTE:** By default, top-level properties are exposed to Java by accessor methods: a getter for a `val` and a getter and a setter for a `var`.
**NOTE:** If we want to declare constant to Java code as `public static final` field, we must use the `const` modifier (this is just allowed for primitive data types as well as for strings):

```kotlin
const val UNIX_LINE_SEPARATOR = "\n" //-> public static final String UNIX_LINE_SEPARATOR = "\n";
```

## Extension Functions
An **extension function** is a function that can be called as a member of a class but is defined outside of it.
To declare an extension function, you need to put the name of the class or interface that you're extending before the name of the function you are adding.

```kotlin
fun String.lastChar() : Char = this.get(this.length - 1)
```
The class name you are extending upon is called the _receiver type_.
The value (or the object) on which you are calling the extension function is called the _receiver object_.

![receiver type and receiver object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dba3bfnh25lo89qb43k2.png)

To call this function, we will use the same syntax for calling ordinary class functions:

```kotlin
println("Kotlin".lastChar()) //this prints n
```

In a sense, we have added a method to the _String_ class. Although _String_ is not part of our code and we do not have access to its code to modify it. It does not even matter if it is any other JVM based language. We can use this feature as long as the code is compiled to a java class.

In the body of extension functions, we can use _this_ as we would use in a method and we can also omit the _this_ keyword, as we can do it in a normal method.
We also have direct access to the methods and properties of the class we are extending (just like the methods of the class). However, we cannot access the _private_ fields and methods of the class. In other words, extension function do NOT allow us to break the encapsulation.

**NOTE:** On the call site, we cannot distinguish extension functions from member functions of the class.

# Importing Extension Functions
When we are defining an extension function, it does not become available across our entire project. So, we have to import the function like any other class or function when we want to use inside other packages:

```kotlin
import strings.lastChar

val c = "Kotlin".lastChar()
```

We can also change the name of the class or function you are importing using the _as_ keyword:

```kotlin
import strings.lastChar as last

val c = "Kotlin".last()
```
## Extension Functions Under the Hood
Under the hood, an extension function is **a static method that accepts the receiver object as its first argument**. Calling an extension function does not involve  creating adapter objects or any other runtime overhead.

To call an extension function from Java, you call the static method and pass the receiver object instance. The name of the class is determined from the name of the file where the function is declared.

```kotlin
char c = StringUtils.lastChar("Java");
```

## Utility Functions as Extensions
Now, we can write the final version of the _joinToString_ function:

```kotlin
fun <T> Collection<T>.joinToString(
    separator: String = ", ",
    prefix: String = "",
    postfix: String = ""
) : String {
    val result = StringBuilder(prefix)
    for((index, element) in this.withIndex()) {
        if (index > 0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}
```
We have made it an extension function to the _Collection_ interface so we can use it like a member of a class. We have also provided default values for all the arguments.

**NOTE:** Because extension functions are effectively syntactic sugar over static method calls, we can use a more specific type as a receiver type, not only a class or interface:

```kotlin
fun Collection<String>.joinToStringSpecificVersion(
    separator: String = ", ",
    prefix: String = "",
    postfix: String = ""
) = joinToString(separator, prefix, postfix)
```
As we can see, we have made the extension function only working for collections of strings. This is possible because they are normal static methods in Java.

**NOTE:** Because extension function are static, they cannot be overridden in subclasses because the function that's called depends on the declared static type of the variable, not on the runtime type of the value stored in that variable. In other words, overriding does not apply to extension functions. Kotlin resolves extension functions statically.

**NOTE:** Member functions always take precedence to the extension functions.

## Extension Properties
Extension properties provide a way to extend classes with APIs that can be accessed using the property syntax, rather than the function syntax.
Even though we call them properties, they cannot have state because there is no place to store them (we cannot add fields to existing instances of Java objects).

```kotlin
val String.lastChar : Char
    get() = get(length - 1)
```
* an extension property looks like a regular property with a receiver type added
* the getter must always be defined (because there's no backing field and no default getter)
* initializers are not allowed either for the same reason

**NOTE:** If we define a property for a mutable object like _StringBuilder_, we can make it a _var_ because the content of it can be modified:

```kotlin
var StringBuilder.lastChar: Char
    get() = get(length - 1)
    set(value: Char) {
        this.setCharAt(length - 1, value)
    }
```

**We can access extension properties exactly like member properties**

```kotlin
println("Kotlin".lastChar) //prints n
val sb = StringBuilder("Kotlin?")
sb.lastChar = '!' //replaces ? with !
println(sb) //prints Kotlin!
```
**NOTE:** To access an extension property from Java, we must invoke its getter explicitly:
```java
StringUtils.getLastChar("Java");
```

## Varargs
In Kotlin, when we call a function to create a list, we can pass any number of arguments to it:
```kotlin
val list = listOf(2, 3, 5, 7, 11)
```
Let's take a look at the `listOf` method to see how it is declared:

```kotlin
fun <T> listOf(vararg values: T) : List<T> = if (values.isNotEmpty()) values.asList() else emptyList()
```
As we can see, Kotlin uses the vararg to declare such library functions. As we know from Java, vararg is **a feature that allows us to pass an arbitrary number of values to a method by packing them in an array**.
Kotlin uses the same concept but with different syntax. In Kotlin, instead of three dots (...), we use the _vararg_ modifier on the parameter.
The other difference between varargs in Java and Kotlin is that in Java we can pass an array as it is to a method argument of vararg. But in Kotlin, we must explicitly unpack the array, so that every element becomes a separate argument to the function being called. This features is called **spread operator**. How should we accomplish this? We should put * character before the corresponding argument:

```kotlin
fun spreadOperator(args: Array<String>) {
    val list = listOf(*args)
    val listWithFixedValue = listOf("args:", *args)
}
```
As we can see in the `listWithFixedValues`, in Kotlin, we can pass some values alongside with the array when we are using varargs parameter. This feature is not supported by Java.

## Infix Calls
In an _infix call_, the method name is placed immediately between the target object name and the parameter, with no extra separators. Infix call can be used with regular methods and extension functions that **have one required parameter**. The _to_ function in the _mapOf_ function to create a map is an infix call:
```kotlin
val map = mapOf(1 to "one", 7 to "seven", 53 to "fifty-three")
```
To declare an infix call for a function, we need to mark it with the _infix_ modifier. Here we can see a simplified version of the _to_ function:
```kotlin
infix fun Any.to(other: Any) = Pair(this, other)
```
Here, the function returns a _Pair_ which is a Kotlin standard library class.

We can also initialize two variables with the contents of a _Pair_ directly:
```kotlin
val (number, name) = 1 to "one"
```
This feature is called **destructuring declaration**.

We can use the destructuring declaration feature in for loop with a map for its keys and values, with collections in a loop to have the element and the index. Let's take a look at some code:

```kotlin
val (pairNumber, pairName) = 1 to "one"

val map = mapOf(1 to "one", 7 to "seven", 53 to "fifty-three")
for ((number, name) in map) {
    println("$number = $name")
}

val list = listOf("one", "seven", "fifty-three")
for ((index, element) in list.withIndex()) {
    println("index $index element is: $element")
}
```

# Local Functions
Kotlin supports local functions: a function inside another function. A local function has access to the variables and parameters of the parent function. This feature is useful to remove duplicate code. As an example, if take a look at the code below, we can see that it has a duplicate code that can be removed:

```kotlin
fun saveUser(user: User) {
    if (user.name.isEmpty()) {
        throw IllegalArgumentException("Can't save user ${user.id}: empty Name")
    }
    if (user.address.isEmpty()) {
        throw IllegalArgumentException("Can't save user ${user.id}: empty Address")
    }
    // save the user to the database
}
```
We can extract the validation logic into a local function, and call that function within the parent function. It reduces the duplicate code, and if we want to change the logic, we can do it in just ONE place! Let's take a look at the code:

```kotlin
fun saveUser(user: User) {
    fun validate(value: String, fieldName: String) {
        if (value.isEmpty())
            throw IllegalArgumentException("Can't save user ${user.id}: empty $fieldName")
    }

    validate(user.name, "Name")
    validate(user.address, "Address")
}
```
As we can see, the local function has access to the parameters of the parent function!

To make the code even more tidy, we can make the _saveUser()_ function an extension function(instead of being a part of the _User_ class). This way, the class is not polluted with a code that is not a part of the class responsibility and not needed by most of the clients(here, just the repository class needs this function to save it to the database!). 

This is the end of part 2 which was the summary of chapter 3. There were other parts in chapter 3 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.