Functions
## Learning Objectives
- Declare and call functions
- Understand parameters and return types
- Use default arguments
- Work with named arguments
- Understand infix functions
- Learn about tail recursion
## Basic Functions
### Function Declaration
```kotlin
fun greet() {
println("Hello!")
}
fun main() {
greet() // Call the function
}
```
### Function with Return Type
```kotlin
fun add(a: Int, b: Int): Int {
return a + b
}
fun main() {
val result = add(5, 3)
println("5 + 3 = $result") // 8
}
```
### Single-Expression Functions
```kotlin
fun double(x: Int): Int = x * 2
fun main() {
println(double(5)) // 10
}
```
## Parameters
### Multiple Parameters
```kotlin
fun printMessage(message: String, count: Int) {
for (i in 1..count) {
println("$i: $message")
}
}
fun main() {
printMessage("Hello", 3)
}
```
### Parameter Types are Required
Unlike return types, parameter types are always required:
```kotlin
// This is valid - return type inferred
fun double(x: Int) = x * 2
// This is INVALID - parameter type is required
// fun double(x) = x * 2
```
## Default Arguments
```kotlin
fun greet(name: String, greeting: String = "Hello") {
println("$greeting, $name!")
}
fun main() {
greet("Alice") // Hello, Alice!
greet("Bob", "Hi") // Hi, Bob!
greet(name = "Charlie", greeting = "Hey") // Hey, Charlie!
}
```
### Default Argument Values
```kotlin
fun createUser(
name: String,
age: Int = 18,
email: String = "unknown@example.com"
) {
println("User: $name, Age: $age, Email: $email")
}
fun main() {
createUser("Alice")
createUser("Bob", 25)
createUser("Charlie", email = "charlie@test.com")
}
```
## Named Arguments
```kotlin
fun configure(
name: String,
debug: Boolean = false,
verbose: Boolean = false
) {
println("Name: $name, Debug: $debug, Verbose: $verbose")
}
fun main() {
configure("MyApp")
configure("MyApp", debug = true)
configure("MyApp", verbose = true, debug = true)
}
```
## Unit Return Type
If a function returns nothing, the return type is `Unit` (optional to declare):
```kotlin
fun printSum(a: Int, b: Int): Unit {
println("Sum: ${a + b}")
}
fun main() {
printSum(3, 4)
}
```
## Single-Expression Body
For simple functions, use the expression body syntax:
```kotlin
fun max(a: Int, b: Int): Int = if (a > b) a else b
fun main() {
println(max(10, 5)) // 10
}
```
## Vararg Parameters
```kotlin
fun printAll(vararg items: String) {
for (item in items) {
println(item)
}
}
fun main() {
printAll("apple", "banana", "cherry")
}
```
Spread operator with arrays:
```kotlin
fun main() {
val fruits = arrayOf("mango", "grape")
printAll("apple", *fruits, "orange")
}
```
## Infix Functions
Functions can be called using infix notation when:
1. They are member functions or extension functions
2. They have exactly one parameter
```kotlin
infix fun Int.times(str: String): String = str.repeat(this)
fun main() {
val result = 3 times "Hi "
println(result) // Hi Hi Hi
}
```
### Custom Pair Creation
```kotlin
fun main() {
val pair = "key" to "value"
println(pair) // (key, value)
// to is actually an infix function
val map = mapOf("a" to 1, "b" to 2)
println(map)
}
```
## Local (Nested) Functions
```kotlin
fun outerFunction() {
fun nestedFunction() {
println("Nested!")
}
nestedFunction()
}
fun main() {
outerFunction()
}
```
Local functions can access variables from the outer scope:
```kotlin
fun findMax(a: Int, b: Int, c: Int): Int {
fun max(x: Int, y: Int) = if (x > y) x else y
return max(max(a, b), c)
}
fun main() {
println(findMax(10, 5, 8)) // 10
}
```
## Generic Functions
```kotlin
fun printItem(item: T) {
println(item)
}
fun main() {
printItem("String")
printItem(42)
printItem(3.14)
}
```
## Tail Recursion
Use `tailrec` modifier for compiler optimization:
```kotlin
tailrec fun factorial(n: Int, acc: Long = 1): Long {
return if (n <= 1) acc else factorial(n - 1, n * acc)
}
fun main() {
println(factorial(10)) // 3628800
}
```
Without `tailrec`, a large recursion would cause stack overflow. The `tailrec` keyword allows the compiler to optimize to an iterative loop.
## Extension Functions
Declared later in detail, but here's a preview:
```kotlin
fun String.addExclamation(): String = this + "!"
fun main() {
val greeting = "Hello".addExclamation()
println(greeting) // Hello!
}
```
## Summary
- Functions declared with `fun` keyword
- Parameters require type annotations
- Return type optional if inferred or returns Unit
- Single-expression functions use `= expression` syntax
- Default arguments reduce need for overloads
- Named arguments improve readability
- `vararg` allows variable number of arguments
- Infix functions called without parentheses
- `tailrec` enables tail recursion optimization
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →