Named & Default Arguments
You can provide argument names during a function call.
Named arguments improve code readability. This is especially true for long and complex argument lists—named arguments can be clear enough that the reader can understand a function call without looking at the documentation.
In this example, all parameters are Int. Named arguments clarify their
meaning:
// NamedAndDefaultArgs/NamedArguments.kt
package color1
import atomictest.eq
fun color(red: Int, green: Int, blue: Int) =
"($red, $green, $blue)"
fun main() {
color(1, 2, 3) eq "(1, 2, 3)" // [1]
color(
red = 76, // [2]
green = 89,
blue = 0
) eq "(76, 89, 0)"
color(52, 34, blue = 0) eq // [3]
"(52, 34, 0)"
}
- [1] This doesn’t tell you much. You’ll have to look at the documentation to know what the arguments mean.
- [2] The meaning of every argument is clear.
- [3] You aren’t required to name all arguments.
Named arguments allow you to change the order of the colors. Here, we specify
blue first:
// NamedAndDefaultArgs/ArgumentOrder.kt
import color1.color
import atomictest.eq
fun main() {
color(blue = 0, red = 99, green = 52) eq
"(99, 52, 0)"
color(red = 255, 255, 0) eq
"(255, 255, 0)"
}
You can mix named and regular (positional) arguments. If you change argument order, you should use named arguments throughout the call—not only for readability, but the compiler often needs to be told where the arguments are.
Named arguments are even more useful when combined with default arguments, which are default values for arguments, specified in the function definition:
// NamedAndDefaultArgs/Color2.kt
package color2
import atomictest.eq
fun color(
red: Int = 0,
green: Int = 0,
blue: Int = 0,
) = "($red, $green, $blue)"
fun main() {
color(139) eq "(139, 0, 0)"
color(blue = 139) eq "(0, 0, 139)"
color(255, 165) eq "(255, 165, 0)"
color(red = 128, blue = 128) eq
"(128, 0, 128)"
}
Any argument you don’t provide gets its default value, so you only need to provide arguments that differ from the defaults. If you have a long argument list, this simplifies the resulting code, making it easier to write and—more importantly—to read.
This example also uses a trailing comma in the definition for color(). The
trailing comma is the extra comma after the last parameter (blue). This is
useful when your parameters or values are written on multiple lines. With a
trailing comma, you can add new items and change their order without adding or
removing commas.
Named and default arguments (as well as trailing commas) also work for constructors:
// NamedAndDefaultArgs/Color3.kt
package color3
import atomictest.eq
class Color(
val red: Int = 0,
val green: Int = 0,
val blue: Int = 0,
) {
override fun toString() =
"($red, $green, $blue)"
}
fun main() {
Color(red = 77).toString() eq "(77, 0, 0)"
}
joinToString() is a standard library function that uses default arguments. It
combines the contents of an iterable (a list, set or range) into a String.
You can specify a separator, a prefix element and a postfix element:
// NamedAndDefaultArgs/CreateString.kt
import atomictest.eq
fun main() {
val list = listOf(1, 2, 3,)
list.toString() eq "[1, 2, 3]"
list.joinToString() eq "1, 2, 3"
list.joinToString(prefix = "(",
postfix = ")") eq "(1, 2, 3)"
list.joinToString(separator = ":") eq
"1:2:3"
}
The default toString() for a List returns the contents in square brackets,
which might not be what you want. The default values for joinToString()s
parameters are a comma for separator and empty Strings for prefix and
postfix. In the above example, we use named and default arguments to specify
only the arguments we want to change.
The initializer for list includes a trailing comma. Normally you’ll only use
a trailing comma when each element is on its own line.
If you use an object as a default argument, a new instance of that object is created for each invocation:
If you pass an object instance as a default argument (da within g() in the
following example), that same instance is used for each call to g(). If you
pass the syntax for a constructor call (DefaultArg() within h()), that
constructor is called every time you call h():
// NamedAndDefaultArgs/Evaluation.kt
package namedanddefault
class DefaultArg
val da = DefaultArg()
fun g(d: DefaultArg = da) = println(d)
fun h(d: DefaultArg = DefaultArg()) =
println(d)
fun main() {
g()
g()
h()
h()
}
/* Sample output:
namedanddefault.DefaultArg@7440e464
namedanddefault.DefaultArg@7440e464
namedanddefault.DefaultArg@49476842
namedanddefault.DefaultArg@78308db1
*/
The output of the two g() calls shows identical object addresses. For the two
calls to h(), the addresses of the DefaultArg objects are different, showing
that there are two distinct objects.
Specify argument names when they improve readability. Compare the following two
calls to joinToString():
// NamedAndDefaultArgs/CreateString2.kt
import atomictest.eq
fun main() {
val list = listOf(1, 2, 3)
list.joinToString(". ", "", "!") eq
"1. 2. 3!"
list.joinToString(separator = ". ",
postfix = "!") eq "1. 2. 3!"
}
It’s hard to guess whether ". " or "" is a separator unless you memorize
the parameter order, which is impractical.
As another example of default arguments, trimMargin() is a standard library
function that formats multi-line Strings. It uses a margin prefix String to
establish the beginning of each line. trimMargin() trims leading whitespace
characters followed by the margin prefix from every line of the source
String. It removes the first and last lines if they are blank:
// NamedAndDefaultArgs/TrimMargin.kt
import atomictest.eq
fun main() {
val poem = """
|->Last night I saw upon the stair
|->A little man who wasn't there
|->He wasn't there again today
|->Oh, how I wish he'd go away."""
poem.trimMargin() eq
"""->Last night I saw upon the stair
->A little man who wasn't there
->He wasn't there again today
->Oh, how I wish he'd go away."""
poem.trimMargin(marginPrefix = "|->") eq
"""Last night I saw upon the stair
A little man who wasn't there
He wasn't there again today
Oh, how I wish he'd go away."""
}
The | (“pipe”) is the default argument for the margin prefix, and you can
replace it with a String of your choosing.
Exercises and solutions can be found at www.AtomicKotlin.com.