**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_ mean almost 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
regular data. A function can be _invoked_ or _called_ to get
that behavior and a return value.
- We have called Kotlin functions already. For example,
```kotlin
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
but different lists of argument types. Such functions
are said to be _overloaded_.
# Writing function types
- Here is how we write function types in Kotlin:
```kotlin
() -> Unit
() -> Int
(Double) -> String
(Int, Double) -> Unit
```
- The parens `()` and arrow `->` symbols are necessary.
They cannot be omitted.
- `() -> Unit` is the type of a function that takes no argument
and returns no useful value.
- `() -> Int` is the type of a function that takes no argument
and returns an Int value.
- `(Double) -> String` is the type of a function that takes a
Double argument and returns a String value.
- `(Int, Double) -> Unit` is the type of a function that takes two
arguments, the first of which is an Int,
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
1. they can be assigned to an element of an aggregate type
like array, and
1. they can be used as a function argument, and
1. 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_
1. _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`,
1. is then followed by the arrow `->`, and
1. finally ends in a sequence of one or more expressions.
# Examples
- This lambda expression denotes a function that takes no argument
and returns `Unit`:
```kotlin
{ -> println("My type is () -> Unit") }
```
It can be abbreviated as
```kotlin
{ println("My type is () -> Unit") }
```
- This lambda expression denotes a function that takes no argument
and returns an Int:
```kotlin
{ -> 42 }
```
It can be abbreviated as
```kotlin
{ 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
```kotlin
{ print("hi"); 1 }
```
is a function that takes no argument,
prints the String "hi" to the screen,
and returns 1.
Its type is
```kotlin
() -> kotlin.Int
```
# 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 representing
a function that takes no parameter, we can omit the `->`.
- It turns out that functions that take exactly one parameter 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` parameter and returns an `Int` result whose
value is twice that of the argument.
We can write `twice` like this
```kotlin
val twice: (Int) -> Int = { 2 * it }
```
instead of the longer
```kotlin
val twice: (Int) -> Int = { i: Int -> 2 * i }
```
# Anonymous functions
- Let's look at this example anonymous function:
```kotlin
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.
- This is an example anonymous function
```kotlin
fun (name: String, score: Int): String {
println("$name scored $score")
return if (score > 95) "exceptional"
else if (score > 90) "excellent"
else "ok"
}
```
- 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
```kotlin
fun (): Unit {
print("Hi there")
return Unit
}
```
we can write
```kotlin
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:
```kotlin
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:
```kotlin
val f = { print("Hi there") }
```
or this:
```kotlin
val f = fun () { print("Hi there") }
```
- 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.,
```kotlin
fun f(): Unit { print("Hi there") }
```
- Of course, since `f` returns `Unit`, its return type can be omitted
to get
```kotlin
fun f() { print("Hi there") }
```
- This is the usual way people define functions in Kotlin!
- 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:
```kotlin
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
```kotlin
fun double(n: Int) = 2 * n
```
# Calling functions using positional arguments
- 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.,
```kotlin
val f: (Int) -> Int = { 2 * it }
// The following call to f returns an Int of value 6.
f(3)
fun g(i: Int, s: String, d: Double) { println("$s $i items is $d") }
/*
The following function call to g will print the string
"The average of 5 items is 1.414", without the quotes,
and return nothing useful.
*/
g(3 + 2, "The average of", 1.414)
```
- This method of calling functions uses _positional arguments_.
Arguments are given in the same _number_, _type_ and _order_
as when the function was defined.
- The parens are needed even for functions that take no arguments,
e.g.,
```kotlin
println()
```
- One calls `member functions` by using the dot notation, e.g.,
```kotlin
val s: String = "hello"
if (s.startsWith("a"))
println("$s starts with 'a'")
```
# 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
```kotlin
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
```kotlin
f("hello")
f("hello", 2)
f("hello", 2, 3.14)
```
are equivalent.
# Calling functions using named arguments
- Functions can also be called by providing the arguments in the
"argument = value" syntax. E.g., for the function `f` defined here
```kotlin
fun f(s: String, i: Int = 2, d: Double = 3.14) { ... }
```
we can call it in many different ways, e.g.,
```kotlin
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.
```kotlin
fun main() {
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
```kotlin
(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
```kotlin