Imagine you’re writing universal domain logic for your program. All I/O is provided via an interface (like UI, persistent storage, networking, etc.), you don’t have to think about it, and you almost don’t care about the platform, on which you run. Your program is fairly simple, only a few straightforward tasks. This chapter describes all essentials you need to write it. The foundational basics that you can build upon: data, processing primitives, and functions to reuse code.
Functions
Functions are an elegant way to reuse parts of your program. They help to split tasks into smaller tasks and allow zooming between levels of abstraction. For example, you don’t have to write code for efficient sorting every time you need to sort your collection. You can reuse an already written routine. Functions define a clear scope, inputs and outputs. Without them, programs would be very long and tedious.
You can even think of your whole program as functions composing into each other, according to an ingenious paradigm called functional programming.
Variadic functions
Function with unlimited number of arguments (of the same type):
fun collect(vararg numbers: Int): List<Int> {
return numbers.toList()
}
It can have also other parameters, but only one can be marked as vararg:
fun collectProxy(mock: List<Int>? = null, vararg numbers: Int): List<Int> {
return mock ?: collect(*numbers)
}
collectProxy(null, 1, 2, 3)
collectProxy(numbers = intArrayOf(1, 2, 3))
Variadic parameter doesn’t have to be the last (although usually it is):
fun collectProxy2(vararg numbers: Int, mock: List<Int>? = null): List<Int> {
return mock ?: collect(*numbers)
}
collectProxy2(1, 2, 3)
collectProxy2(mock = listOf(1, 2, 3))