Skip to content

Commit 85b7230

Browse files
committed
second pass
1 parent d76ff97 commit 85b7230

File tree

1 file changed

+91
-55
lines changed

1 file changed

+91
-55
lines changed

docs/topics/functions.md

Lines changed: 91 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ fun powerOf(
4444
This helps with refactorings and code maintenance:
4545
you can move parameters within the declaration without worrying about which is going to be the last one.
4646

47-
TODO should this be optional parameters? probably not
48-
### Parameters with default values
47+
### Parameters with default values (optional parameters)
4948

5049
Function parameters can have default values, which are used when you skip the corresponding argument.
51-
A default value is set by appending `=` to the type.
52-
This reduces the number of overloads:
50+
This reduces the number of necessary overloads.
51+
Parameters with default values are also referred to as _optional parameters_.
52+
53+
A default value is set by appending `=` to the parameter declaration:
5354

5455
```kotlin
5556
fun read(
@@ -59,50 +60,85 @@ fun read(
5960
) { /*...*/ }
6061
```
6162

62-
Such parameters are also referred to as _optional parameters_.
63+
If a parameter with default value precedes a parameter with no default value, the default value can only be used by calling
64+
the function with [named arguments](#named-arguments):
65+
66+
```kotlin
67+
fun foo(
68+
foo: Int = 0,
69+
bar: Int,
70+
) { /*...*/ }
6371

64-
Overriding methods always use the base method's default parameter values.
72+
foo(bar = 1) // Uses the default value foo = 0
73+
foo(1) // Error: No value passed for parameter 'bar'
74+
```
75+
76+
[Overriding methods](inheritance.md#overriding-methods) always use the base method's default parameter values.
6577
When overriding a method that has default parameter values, the default parameter values must be omitted from the signature:
6678

6779
```kotlin
6880
open class A {
69-
open fun foo(i: Int = 10) { /*...*/ }
81+
open fun foo(i: Int = 10, j: Int = 0) { /*...*/ }
7082
}
7183

7284
class B : A() {
73-
override fun foo(i: Int) { /*...*/ } // No default value is allowed.
85+
// It's not allowed to specify default values here
86+
// but this function also uses 10 for 'i' and 0 for 'j'
87+
// by default.
88+
override fun foo(i: Int, j: Int) { /*...*/ }
7489
}
7590
```
7691

77-
If a parameter with default value precedes a parameter with no default value, the default value can only be used by calling
78-
the function with [named arguments](#named-arguments):
92+
#### Non-constant expressions as default values
93+
94+
You can assign to a parameter a default value that is not constant an expression, as in a function call, or a calculation that uses
95+
values of other arguments, like the `len` parameter in the example above:
7996

8097
```kotlin
81-
fun foo(
82-
bar: Int = 0,
83-
baz: Int,
98+
fun read(
99+
b: ByteArray,
100+
off: Int = 0,
101+
len: Int = b.size,
102+
) { /*...*/ }
103+
```
104+
105+
Parameters referring to other parameters' values must be declared later in the order (in this example, `len` must be declared after `b`).
106+
107+
In general default value of a parameter can be any expression — but such expressions are only calculated when
108+
the function is called **without** the parameter and a default value needs to be assigned.
109+
For example, this function prints out a line when it is called without the `print` parameter:
110+
111+
```kotlin
112+
fun read(
113+
b: Int,
114+
print: Unit? = println("No argument passed for 'print'.")
84115
) { /*...*/ }
85116

86-
foo(baz = 1) // The default value bar = 0 is used
117+
fun main() {
118+
read (1)
119+
}
87120
```
88121

89-
TODO this doesn't seem to do much with the subject of default values.
90-
If the last parameter after all parameters with default values has a functional type,
122+
If the last parameter in a function declaration has a functional type,
91123
then you can pass the corresponding [lambda](lambdas.md#lambda-expression-syntax) argument either as a named argument or [outside the parentheses](lambdas.md#passing-trailing-lambdas):
92124

93125
```kotlin
94126
fun foo(
95-
bar: Int = 0,
96-
baz: Int = 1,
127+
foo: Int = 0,
128+
bar: Int = 1,
97129
qux: () -> Unit,
98130
) { /*...*/ }
99131

100-
foo(1) { println("hello") } // Uses the default value baz = 1
101-
foo(qux = { println("hello") }) // Uses both default values bar = 0 and baz = 1
102-
foo { println("hello") } // Uses both default values bar = 0 and baz = 1
132+
// Uses the default value bar = 1
133+
foo(1) { println("hello") }
134+
135+
// Uses both default values foo = 0 and bar = 1
136+
foo(qux = { println("hello") })
137+
138+
// Uses both default values foo = 0 and bar = 1
139+
foo { println("hello") }
103140
```
104141

105-
TODO should named arguments be before default values? Should arguments be parameters?
106142
### Named arguments
107143

108144
You can name one or more of a function's arguments when calling it. This can be helpful when a function has many
@@ -148,55 +184,43 @@ skipped argument, you must name all subsequent arguments:
148184
reformat("This is a short String!", upperCaseFirstLetter = false, wordSeparator = '_')
149185
```
150186

151-
You can pass a [variable number of arguments (`vararg`)](#variable-number-of-arguments-varargs) with names using the
152-
_spread_ operator (prefix the array with `*`):
187+
You can pass a [variable number of arguments](#variable-number-of-arguments-varargs) (`vararg`) naming the correspoding array:
153188

154189
```kotlin
155190
fun foo(vararg strings: String) { /*...*/ }
156191

157-
foo(strings = *arrayOf("a", "b", "c"))
192+
foo(strings = arrayOf("a", "b", "c"))
158193
```
159194

195+
<!-- Rationale for named arguments interaction with varargs is here https://youtrack.jetbrains.com/issue/KT-52505#focus=Comments-27-6147916.0-0 -->
196+
160197
> When calling Java functions on the JVM, you can't use the named argument syntax because Java bytecode does not
161198
> always preserve the names of function parameters.
162199
>
163200
{style="note"}
164201

165202
### Unit-returning functions
166203

167-
If a function does not return a useful value, its return type is `Unit`. `Unit` is a type with only one value - `Unit`.
168-
This value does not have to be returned explicitly:
204+
If a function does not return a useful value, its return type is `Unit` (corresponds to the `void` type in Java).
205+
206+
`Unit` is a type with only one value - `Unit`.
207+
You don't have to declare this return type, or return `Unit` explicitly.
208+
Therefore, this verbose declaration:
169209

170210
```kotlin
171211
fun printHello(name: String?): Unit {
172212
if (name != null)
173213
println("Hello $name")
174214
else
175215
println("Hi there!")
176-
// `return Unit` or `return` is optional
216+
return Unit
177217
}
178218
```
179219

180-
TODO this can be folded into above surely
181-
The `Unit` return type declaration is also optional. The above code is equivalent to:
220+
is equivalent to:
182221

183222
```kotlin
184-
fun printHello(name: String?) { ... }
185-
```
186-
187-
TODO since this refers to explicit return types, should probably be below them.
188-
### Single-expression functions
189-
190-
When the function body consists of a single expression, the curly braces can be omitted and the body specified after an `=` symbol:
191-
192-
```kotlin
193-
fun double(x: Int): Int = x * 2
194-
```
195-
196-
Explicitly declaring the return type is [optional](#explicit-return-types) when this can be inferred by the compiler:
197-
198-
```kotlin
199-
fun double(x: Int) = x * 2
223+
fun printHello(name: String?) { /*...*/ }
200224
```
201225

202226
### Explicit return types
@@ -249,6 +273,20 @@ val a = intArrayOf(1, 2, 3) // IntArray is a primitive type array
249273
val list = asList(-1, 0, *a.toTypedArray(), 4)
250274
```
251275

276+
### Single-expression functions
277+
278+
When the function body consists of a single expression, the curly braces can be omitted and the body specified after an `=` symbol:
279+
280+
```kotlin
281+
fun double(x: Int): Int = x * 2
282+
```
283+
284+
Explicitly declaring the return type is [optional](#explicit-return-types) when this can be inferred by the compiler:
285+
286+
```kotlin
287+
fun double(x: Int) = x * 2
288+
```
289+
252290
### Infix notation
253291

254292
Functions marked with the `infix` keyword can also be called using the infix notation (omitting the dot and the parentheses
@@ -300,10 +338,8 @@ class MyStringCollection {
300338

301339
## Function scope
302340

303-
TODO is comparison to other languages even necessary here
304-
Kotlin functions can be declared at the top level in a file, meaning you do not need to create a class to hold a function,
305-
which you are required to do in languages such as Java and C#. In addition
306-
to top level functions, Kotlin functions can also be declared locally as member functions and extension functions.
341+
Kotlin functions can be declared at the top level in a file, meaning you do not need to create a class to hold a function.
342+
Functions can also be declared locally as _member functions_ and _extension functions_.
307343

308344
### Local functions
309345

@@ -375,10 +411,10 @@ the recursion, leaving behind a fast and efficient loop based version instead:
375411
val eps = 1E-10 // "good enough", could be 10^-15
376412

377413
tailrec fun findFixPoint(x: Double = 1.0): Double =
378-
if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x))
414+
if (abs(x - cos(x)) < eps) x else findFixPoint(cos(x))
379415
```
380416

381-
This code calculates the fixed point of cosine (a mathematical constant). It simply calls `Math.cos` repeatedly
417+
This code calculates the fixed point of cosine (a mathematical constant). It simply calls `cos()` repeatedly
382418
starting at `1.0` until the result no longer changes, yielding a result of `0.7390851332151611` for the specified
383419
`eps` precision. The resulting code is equivalent to this more traditional style:
384420

@@ -388,9 +424,9 @@ val eps = 1E-10 // "good enough", could be 10^-15
388424
private fun findFixPoint(): Double {
389425
var x = 1.0
390426
while (true) {
391-
val y = Math.cos(x)
392-
if (Math.abs(x - y) < eps) return x
393-
x = Math.cos(x)
427+
val y = cos(x)
428+
if (abs(x - y) < eps) return x
429+
x = cos(x)
394430
}
395431
}
396432
```

0 commit comments

Comments
 (0)