# Topics

• Function types
• Function literals
• lambda expressions
• anonymous functions
• Defining functions
• Calling functions
• Nested functions
• Higher-order functions

# Function types

• A function is an abstraction of behavior.
• A function takes in zero or more arguments, and may or may not return a useful value.
• Kotlin defines a special type called Unit. The Unit type has only one value, also called Unit.
• A function that returns no useful value is assumed by Kotlin to return Unit. In this way, one can say that every Kotlin function returns a value.
• The type of a function is determined by its list of parameter types, and its return type.
• Note that the terms argument and parameter almost mean the same thing. We call something an argument when it appears in a function call, and call it a parameter when it appears in the function definition.

# Examples

• What distinguishes a value of function type from values of other types is that a function value denotes a behavior, while other types denote data. A function value can be invoked or called to get that behavior and a return value.
• We have called Kotlin functions already. For example,

print("Value of a is ") // line 1
print(1)                // line 2
println()               // line 3
• The print function called in Line 1 takes a String argument and returns Unit.
• The print function called in Line 2 takes an Int argument and returns Unit.
• The println function called in Line 3 takes no argument and returns Unit.
• The print function in Line 1 is not the same as the print function in Line 2. Kotlin allows two different functions to have the same name so long as they have different lists of argument types. Such functions are said to be overloaded.

# Writing function types

• Here is how we write function types in Kotlin:

() -> Unit
() -> Int
(Double) -> String
(Int, Double) -> Unit
• The parens () and arrow -> symbols are necessary. They cannot be omitted.
• () -> Unit is the function type that takes no argument and returns no useful value.
• () -> Int is the function type that takes no argument and returns an Int value.
• (Double) -> String is the function type that takes a Double argument and returns a String value.
• (Int, Double) -> Unit is the function type that takes two arguments, the first of which is an Int and the second of which is a Double, and returns no useful value.

# First-class citizens

• Values of the basic types we have studied are called first-class citizens because
1. they can be assigned to a variable, and
2. they can be assigned to an element of an aggregate type like array, and
3. they can be used as a function argument, and
4. they can be returned from a function
• Kotlin functions are also first-class citizens!

# Function literals

• A function literal is a source-code-level way to write a function value.
• Kotlin has two kinds of function literals:
1. lambda expressions
2. anonymous functions
• Just like literals of other types, function literals are meant to be used in a context where the value is used and immediately thrown away, like in an expression.

# Syntax of lambda expressions

• Syntactically, a lambda expression has a body enclosed in a pair of opening and closing braces.
• The body has three parts. It
1. starts with a list of comma-separated parameter declaration name : type,
2. is then followed by the arrow ->, and
3. finally ends in a sequence of one or more expressions.

# Examples

• This lambda expression denotes a function that takes no argument and returns Unit:

{ -> println("My type is () -> Unit") }

It can be abbreviated as

{ println("My type is () -> Unit") }
• This lambda expression denotes a function that takes no argument and returns an Int:

{ -> 42 }

It can be abbreviated as

{ 42 }
• Note that for functions that take no arguments, the arrow can be omitted.

# Return values of lambda expressions

• The return value of a lambda expression is the value of the last expression before the closing brace.
• E.g., this lambda expression

{ print("hi"); 1 }

has type

() -> kotlin.Int

It represents the function that takes no argument, prints the String “hi” to the screen, and returns 1.

# Exercise

• List the similarities and differences between a block and a lambda expression.

# What is it?

• We have mentioned that when writing a lambda expression that represents a function that takes no argument, we can omit the ->.
• It turns out that functions that take exactly one argument are used so often that Kotlin provides a syntactic sugar to allow us to sometimes omit the name and type of the sole function parameter, and the -> as well. In such a case, we use the default name it for that parameter.
• Here is an example. We want to define a function twice that takes a single Int argument and returns an Int result whose value is twice that of the argument. We can write twice like this

val twice: (Int) -> Int = { 2 * it }

instead of the longer

val twice: (Int) -> Int = { i: Int -> 2 * i }

# Syntax of anonymous functions

• Let’s look at this example anonymous function:

fun (): Int {
print("hi")
return 1
}
• It denotes exactly the same function represented by the lambda expression { print("hi"); 1 }.
• Syntactically, an anonymous function starts with the keyword fun followed by a list of comma-separated arguments with type annotations enclosed in a pair of parentheses, followed by a colon and the return type. It finally ends in a block body.
• Within its body there must be at least one return statement if the function returns a non-Unit value.

# Anonymous function example

• This is an example anonymous function

fun (name: String, score: Int): String {
println("$name scored$score")
return if (score > 95) "exceptional"
else if (score > 90) "excellent"
else "ok"
}

# Syntax of anonymous functions, continued

• In case the function returns Unit, we can omit the return type annotation : Unit and the return statement return Unit. For example, instead of writing

fun (): Unit {
print("Hi there")
return Unit
}

we can write

fun () {
print("Hi there")
}

instead.

# Defining functions

• We can define a function using the same syntax as when we define variables. That is, we write var or val, then write the function name (and type annotation if needed), then write =, then write either a lambda expression or an anonymous function.
• E.g. either one of these two ways work fine:

val f: () -> Unit = { print("Hi there") }
val f = fun (): Unit { print("Hi there") }
• With the help of type inference, we can write even more succinctly like this:

val f = { print("Hi there") }

or this:

val f = fun () { print("Hi there") }

# Defining functions, continued

• Another way to define a function is to take an anonymous function and insert the name of the function to be defined after the keyword fun, e.g.,

fun f(): Unit { print("Hi there") }
• Of course, since f returns Unit, its return type can be omitted to get

fun f() { print("Hi there") }
• This is the usual way people define functions in Kotlin!

# Defining functions, continued

• One syntactic sugar is that if the body of the function consists of only one expression, we can remove the braces and use the = sign to define the function, like this:

fun double(n: Int): Int = 2 * n
• One further simplification is that in case the return type can be inferred from the expression, we can omit it all together. So the above can be written

fun double(n: Int) = 2 * n

# Calling functions

• Functions are called by writing any expression that evaluates to a function value, followed by the comma-delimited arguments, surrounded by a pair of parentheses. E.g.,

val f: (Int) -> Int = { 2 * it }
// The following call to f returns an Int of value 6.
f(3)

# Default arguments

• Function parameters can be specified to take on default values. These default values are used when the corresponding arguments are omitted at function call. E.g., if a function f is defined as

fun f(s: String, i: Int = 2, d: Double = 3.14) { ... }
• Then f can be called by giving it 1, 2 or 3 arguments. E.g., all these 3 function calls

f("hello")
f("hello", 2)
f("hello", 2, 3.14)

are equivalent.

# Named arguments

• Functions can also be called by providing the arguments in the “argument = value” syntax. E.g., for the function f defined here

fun f(s: String, i: Int = 2, d: Double = 3.14) { ... }

we can call it in many different ways, e.g.,

f(i = 3, s = "Alice", d = 1.2)      // line 1
f(d = 2.1, s = "Bob")               // line 2
f("Charlie", d = 0.3)               // line 3
• The call in line 1 shows that we can provide the named arguments in any order.
• The call in line 2 shows that we can still use default arguments when using named arguments.
• The call in line 3 shows that we can combine positional arguments and named arguments in the same call, as long as we provide all the positional arguments first.

# Nested functions

• One function g can be defined locally within the definition of another function f.
• In such a case,
• g is a local function of f, i.e., it is visible only within f starting from g’s point of definition.
• g can see all definitions of f that occur before g’s point of definition.
• Functions can be nested arbitrarily deeply.

# Example nested function

• Here is a simple example of nested function.

fun main(args: Array<String>) {
val basic = "ho"
fun three(s: String) = s.repeat(3)
fun ten(s: String) = "\$s ".repeat(10)
fun greeting() = ten(three(basic))
println(greeting())
}

This program prints

hohoho hohoho hohoho hohoho hohoho hohoho hohoho hohoho hohoho hohoho 

# Higher-order functions

• A higher-order function is one that
1. takes some other function(s) as argument(s), and/or
2. returns a function value.
• Thus, higher-order functions will have types that look something like

(Int) -> (Int) -> Int
((Int) -> Int) -> Int
(Int, (Int, Double) -> Char) -> String
(Int, Int, Double) -> (Char) -> String
((Double) -> Double,  (Double) -> Double) -> (Double) -> Double
(((Double) -> Double,  (Double) -> Double) -> Double) -> Double

# Function argument

• A good example of a higher-order function that takes a function argument is the array constructors.
• We’ll look at the constructor for IntArray as an example but what we’ll learn will be applicable to constructors of all array types.

# IntArray constructor

• A function that is associated with an object is called a member function.
• A constructor is a special kind of member function. It’s used to construct a new object of that type.
• Syntactically, a constructor is called with the type name, e.g. the constructor for an IntArray is called IntArray. The IntArray constructor has this signature

<init>(size: Int, init: (Int) -> Int = { 0 })
• This is what it all means.
• The first parameter of the constructor is called size and has type Int; it specifies how many Ints the array will contain.
• The second parameter is called init and has type (Int) -> Int, and, unless told otherwise, will initialize all array elements to 0 by default.
• The init function parameter takes an argument which is the array index, and returns a value to be initialized for that indexed element.

# IntArray constructor

• Here are some example calls to construct new IntArray’s.

/*
* The init function is not given, so a1 will be a new array of 3 Ints,
* with each element initialized to 0.
*/
val a1 = IntArray(3)

/*
* The init function is given, so a2 will be a new array of 3 Ints,
* with elements initialized so that a2[0] = 0, a2[1] = 1, a2[2] = 2.
*/
val a2 = IntArray(3, { it })

/*
* The init function is given, so a3 will be a new array of 3 Ints,
* with elements initialized so that a3[0] = 3, a3[1] = 2, a3[2] = 1.
*/
val a3 = IntArray(3, { 3-it })

# A syntactic sugar

• When the last argument of a function call is a lambda expression, Kotlin allows us to write it outside of the parens. E.g., the line

val a3 = IntArray(3, { 3-it })

can be written as

val a3 = IntArray(3) {
3-it
}

and this is the preferred way to write such a function call.

# Arrays of non-primitive types

• What we learn about the constructor for IntArray applies to constructors for arrays of other types as well.
• E.g., to create an array of five Strings and initialize every element to an empty string, you should write

val stringArray = Array<String>(5) { "" }
• There is also a general builder function called arrayOf that can construct an array of any type, and at the same time initialize their elements to the values you provide with the call.
• E.g., this line

val names = arrayOf("Alice", "Bob", "Charlie")

will create an array of 3 strings and assign it to the variable names. It also initializes names[0] with the string “Alice”, names[1] with “Bob”, and names[2] with “Charlie”.

# Two-dimensional arrays

• For each integer $$n>1$$, Kotlin implements an $$n$$-dimensional array as an array of $$(n-1)$$-dimensional array.
• E.g., a two-dimensional array (what we call matrix in mathematics) of Ints is simply an array of IntArray, i.e., its type is

Array<IntArray>
• Here are some example creation of 2d-arrays in Kotlin.

// The 3x3 zero matrix.
val zero3 = Array<IntArray>(3) { IntArray(3) }

// The 3x3 identity matrix.
val id3 = Array<IntArray>(3) { i ->
IntArray(3) { j ->
if (i == j) 1 else 0
}
}

# Function returning function value

• In mathematics, if you have two functions $$f:A\to B$$ and $$g:B\to C$$, you can form the composite function $$g\circ f$$, where $$(g \circ f): A \to C$$ such that $$(g\circ f)(a) = g(f(a))$$ for all $$a\in A$$.
• Here is a special case of function composition in Kotlin:

fun o(
f: (Double) -> Double,
g: (Double) -> Double): (Double)->Double = { g(f(it)) }
It’s a special case because we are restricting the sets $$A$$, $$B$$, and $$C$$ to be Double.
• With the definition of o above, we can now write

fun f(x: Double) = x + 2.0
fun g(x: Double) = x * x
println(o(::f, ::g)(1.0))  // This will print 9.0
• The :: is the function reference operator. Written in front of a function name, it means we want to reference that function instead of calling it.