Skip to content

Commit

Permalink
chore(doc): update functions to idea theme
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderPrendota committed Jul 13, 2018
1 parent 4fc3c3f commit d0a56b3
Showing 1 changed file with 69 additions and 19 deletions.
88 changes: 69 additions & 19 deletions pages/docs/reference/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,53 +11,60 @@ title: "Functions: infix, vararg, tailrec"

Functions in Kotlin are declared using the *fun*{: .keyword } keyword:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun double(x: Int): Int {
return 2 * x
}
```
</div>

## Function Usage

Calling functions uses the traditional approach:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
val result = double(2)
```
</div>


Calling member functions uses the dot notation:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
Sample().foo() // create instance of class Sample and call foo
```
</div>

### Parameters

Function parameters are defined using Pascal notation, i.e. *name*: *type*. Parameters are separated using commas. Each parameter must be explicitly typed:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun powerOf(number: Int, exponent: Int) {
...
}
fun powerOf(number: Int, exponent: Int) { ... }
```
</div>

### Default Arguments

Function parameters can have default values, which are used when a corresponding argument is omitted. This allows for a reduced number of overloads compared to
other languages:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
...
}
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) { ... }
```
</div>

Default values are defined using the **=** after type along with the value.

Overriding methods always use the same default parameter values as the base method.
When overriding a method with default parameters values, the default parameter values must be omitted from the signature:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
open class A {
open fun foo(i: Int = 10) { ... }
Expand All @@ -67,30 +74,36 @@ class B : A() {
override fun foo(i: Int) { ... } // no default value allowed
}
```
</div>

If a default parameter precedes a parameter with no default value, the default value can be used only by calling the function with [named arguments](#named-arguments):

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun foo(bar: Int = 0, baz: Int) { /* ... */ }
fun foo(bar: Int = 0, baz: Int) { ... }

foo(baz = 1) // The default value bar = 0 is used
```
</div>

But if a last argument [lambda](lambdas.html#lambda-expression-syntax) is passed to a function call outside the parentheses, passing no values for the default parameters is allowed:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun foo(bar: Int = 0, baz: Int = 1, qux: () -> Unit) { /* ... */ }
fun foo(bar: Int = 0, baz: Int = 1, qux: () -> Unit) { ... }

foo(1) { println("hello") } // Uses the default value baz = 1
foo { println("hello") } // Uses both default values bar = 0 and baz = 1
```
</div>

### Named Arguments

Function parameters can be named when calling functions. This is very convenient when a function has a high number of parameters or default ones.

Given the following function:

<div class="sample" markdown="1" theme="idea" data-highlight-only auto-indent="false">
``` kotlin
fun reformat(str: String,
normalizeCase: Boolean = true,
Expand All @@ -100,21 +113,27 @@ fun reformat(str: String,
...
}
```
</div>

we could call this using default arguments:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
reformat(str)
```
</div>

However, when calling it with non-default, the call would look something like:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
reformat(str, true, true, false, '_')
```
</div>

With named arguments we can make the code much more readable:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
reformat(str,
normalizeCase = true,
Expand All @@ -123,22 +142,27 @@ reformat(str,
wordSeparator = '_'
)
```
</div>

and if we do not need all arguments:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
reformat(str, wordSeparator = '_')
```
</div>

When a function is called with both positional and named arguments, all the positional arguments should be placed before the first named one. For example, the call `f(1, y = 2)` is allowed, but `f(x = 1, 2)` is not.

[Variable number of arguments (*vararg*{: .keyword })](#variable-number-of-arguments-varargs) can be passed in the named form by using the **spread** operator:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun foo(vararg strings: String) { /* ... */ }
fun foo(vararg strings: String) { ... }

foo(strings = *arrayOf("a", "b", "c"))
```
</div>

Note that the named argument syntax cannot be used when calling Java functions, because Java bytecode does not
always preserve names of function parameters.
Expand All @@ -148,6 +172,7 @@ always preserve names of function parameters.
If a function does not return any useful value, its return type is `Unit`. `Unit` is a type with only one value - `Unit`. This
value does not have to be returned explicitly:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun printHello(name: String?): Unit {
if (name != null)
Expand All @@ -157,28 +182,33 @@ fun printHello(name: String?): Unit {
// `return Unit` or `return` is optional
}
```
</div>

The `Unit` return type declaration is also optional. The above code is equivalent to:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun printHello(name: String?) {
...
}
fun printHello(name: String?) { ... }
```
</div>

### Single-Expression functions

When a function returns a single expression, the curly braces can be omitted and the body is specified after a **=** symbol:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun double(x: Int): Int = x * 2
```
</div>

Explicitly declaring the return type is [optional](#explicit-return-types) when this can be inferred by the compiler:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun double(x: Int) = x * 2
```
</div>

### Explicit return types

Expand All @@ -191,6 +221,7 @@ type will be non-obvious to the reader (and sometimes even for the compiler).

A parameter of a function (normally the last one) may be marked with `vararg` modifier:

<div class="sample" markdown="1" theme="idea" data-highlight-only auto-indent="false">
``` kotlin
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
Expand All @@ -199,12 +230,15 @@ fun <T> asList(vararg ts: T): List<T> {
return result
}
```
</div>

allowing a variable number of arguments to be passed to the function:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
val list = asList(1, 2, 3)
```
</div>

Inside a function a `vararg`-parameter of type `T` is visible as an array of `T`, i.e. the `ts` variable in the example above has type `Array<out T>`.

Expand All @@ -215,10 +249,12 @@ a lambda outside parentheses.
When we call a `vararg`-function, we can pass arguments one-by-one, e.g. `asList(1, 2, 3)`, or, if we already have an array
and want to pass its contents to the function, we use the **spread** operator (prefix the array with `*`):

<div class="sample" markdown="1" theme="idea" data-highlight-only>
```kotlin
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
```
</div>

### Infix notation

Expand All @@ -228,17 +264,17 @@ Functions marked with the *infix*{: .keyword } keyword can also be called using
* They must have a single parameter;
* The parameter must not [accept variable number of arguments](#variable-number-of-arguments-varargs) and must have no [default value](#default-arguments).

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
infix fun Int.shl(x: Int): Int {
// ...
}
infix fun Int.shl(x: Int): Int { ... }

// calling the function using the infix notation
1 shl 2

// is the same as
1.shl(2)
```
</div>

> Infix function calls have lower precedence than the arithmetic operators, type casts, and the `rangeTo` operator.
> The following expressions are equivalent:
Expand All @@ -257,9 +293,10 @@ Note that infix functions always require both the receiver and the parameter to
calling a method on the current receiver using the infix notation, you need to use `this` explicitly; unlike regular method calls,
it cannot be omitted. This is required to ensure unambiguous parsing.

<div class="sample" markdown="1" theme="idea" data-highlight-only>
```kotlin
class MyStringCollection {
infix fun add(s: String) { /* ... */ }
infix fun add(s: String) { ... }

fun build() {
this add "abc" // Correct
Expand All @@ -268,6 +305,7 @@ class MyStringCollection {
}
}
```
</div>


## Function Scope
Expand All @@ -279,6 +317,7 @@ to top level functions, Kotlin functions can also be declared local, as member f

Kotlin supports local functions, i.e. a function inside another function:

<div class="sample" markdown="1" theme="idea" data-highlight-only auto-indent="false">
``` kotlin
fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: Set<Vertex>) {
Expand All @@ -290,9 +329,11 @@ fun dfs(graph: Graph) {
dfs(graph.vertices[0], HashSet())
}
```
</div>

Local function can access local variables of outer functions (i.e. the closure), so in the case above, the *visited* can be a local variable:

<div class="sample" markdown="1" theme="idea" data-highlight-only auto-indent="false">
``` kotlin
fun dfs(graph: Graph) {
val visited = HashSet<Vertex>()
Expand All @@ -305,34 +346,39 @@ fun dfs(graph: Graph) {
dfs(graph.vertices[0])
}
```
</div>

### Member Functions

A member function is a function that is defined inside a class or object:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
class Sample() {
fun foo() { print("Foo") }
}
```
</div>

Member functions are called with dot notation:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
Sample().foo() // creates instance of class Sample and calls foo
```
</div>

For more information on classes and overriding members see [Classes](classes.html) and [Inheritance](classes.html#inheritance).

## Generic Functions

Functions can have generic parameters which are specified using angle brackets before the function name:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
fun <T> singletonList(item: T): List<T> {
// ...
}
fun <T> singletonList(item: T): List<T> { ... }
```
</div>

For more information on generic functions see [Generics](generics.html).

Expand All @@ -354,13 +400,16 @@ Kotlin supports a style of functional programming known as [tail recursion](http
This allows some algorithms that would normally be written using loops to instead be written using a recursive function, but without the risk of stack overflow.
When a function is marked with the `tailrec` modifier and meets the required form, the compiler optimises out the recursion, leaving behind a fast and efficient loop based version instead:

<div class="sample" markdown="1" theme="idea" data-highlight-only auto-indent="false">
``` kotlin
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
```
</div>

This code calculates the fixpoint of cosine, which is a mathematical constant. It simply calls Math.cos repeatedly starting at 1.0 until the result doesn't change any more, yielding a result of 0.7390851332151607. The resulting code is equivalent to this more traditional style:

<div class="sample" markdown="1" theme="idea" data-highlight-only>
``` kotlin
private fun findFixPoint(): Double {
var x = 1.0
Expand All @@ -371,5 +420,6 @@ private fun findFixPoint(): Double {
}
}
```
</div>

To be eligible for the `tailrec` modifier, a function must call itself as the last operation it performs. You cannot use tail recursion when there is more code after the recursive call, and you cannot use it within try/catch/finally blocks. Currently tail recursion is only supported in the JVM backend.

0 comments on commit d0a56b3

Please sign in to comment.