Function declarations
A function gives a block of statements a name, a list of typed parameters and, optionally, a result type. Calling it runs the block with the arguments bound to the parameters, and the call is worth the value the block returns.
function = [ attributes ] [ "pub" ] "func" name [ type-parameters ]
"(" [ parameter { "," parameter } [ "," ] ] ")" [ "->" result ] block
parameter = name ":" type [ "=" expression ]
| name ":" type "..."
result = type | type "!" type | "!" type
func Add(left: int, right: int) -> int {
return left + right;
}
| Part | In Add | Meaning |
|---|---|---|
| Name | Add | An identifier; PascalCase by convention |
| Parameters | left: int, right: int | name: Type each, separated by commas; a trailing comma is allowed |
| Result type | -> int | The type of the value the function returns; omitted when there is none |
| Body | { return left + right; } | A block |
Parameters, default values and variadic parameters are described in Parameters. A name in angle brackets after the function name declares a type parameter, which makes the function generic.
Where functions are declared
| Place | Declares |
|---|---|
| The top level of a file | A free function of the package's root module |
A module A::B { } block | A free function of that module — see Modules |
An extend T { } block | A method, constructor, operator or destructor of T |
An extern { } block | A foreign function, without a body — see FFI |
asm func | A function whose body is assembly — see Assembly |
Every other function needs a body. A signature ending in ; is refused:
error: function 'Later' has no body
Declaration order does not matter: a function may call one declared further down the file, or in another file of the package. pub makes a function visible to other packages; see Visibility.
The result
| Written | The function |
|---|---|
no -> | Returns nothing. A bare return; leaves early; reaching the closing brace returns |
-> T | Returns a T. Every path through the body must end in return with a value |
-> () | Returns the unit value () |
-> T ! E, -> ! E | Is fallible: it returns a T (or nothing) or fails with an E |
Several values are returned as a tuple, an absent result as an optional.
func Greet(name: char8[..]) {
if name.length == 0 {
return;
}
PrintLine("Hello, {}!", name);
}
func Divide(dividend: int, divisor: int) -> (int, int) {
return (dividend / divisor, dividend % divisor);
}
The compiler checks that a function with a result type returns on every path, and that a function without one never returns a value:
error: function 'Sign' must return a value of type 'int' on every control-flow path
error: 'return' cannot have a value in a function with no return type
Leaving out the result type is not the same as writing -> (). Only a unit-returning function produces a value of type () that can be stored or passed; a call to a function without a result is written as a statement on its own. See return for the statement itself.
Calls
A call is the function's name followed by one argument per parameter, in parentheses and in order. Arguments are evaluated from left to right, then bound to the parameters, and the body runs:
func Note(label: char8[..], value: int) -> int {
PrintLine("evaluating {}", label);
return value;
}
func Main() -> int {
// Prints "evaluating first", then "evaluating second", then 12.
PrintLine("{}", Pair(Note("first", 1), Note("second", 2)));
return 0;
}
func Pair(first: int, second: int) -> int {
return first * 10 + second;
}
A call is an expression of the result type and may appear wherever a value of that type fits — as an argument to another call, in an operator, on the right of a binding.
Each argument must have its parameter's type. Nothing is converted to make a call fit, with one exception: an unsuffixed integer literal takes the integer type of its parameter, so Half(9) works for a uint8 parameter. A function may call itself, directly or through others; each call has its own parameters and locals.
Rules and errors
| Mistake | Error |
|---|---|
| An argument of another type | argument 1 to 'Square' has type 'float64', but parameter 'value' requires 'int' |
| Too many or too few arguments | call to 'Square' expects 1 argument, but 2 were provided |
| A name in the wrong case | name 'square' is not defined in this scope, with did you mean 'Square'? |
A missing return on some path | function 'Sign' must return a value of type 'int' on every control-flow path |
| A value returned from a function without a result | 'return' cannot have a value in a function with no return type |
A body-less signature outside extern | function 'Later' has no body |
Names are case-sensitive. Several functions may share a name when their parameters differ; see Overloading.
See also
- Parameters — by-value parameters, defaults and variadics
- Function types — functions as values
- Main — the entry point of a program
- Generics — functions over type parameters
- Learn: Function, Return, Recursion
Patterns
Every pattern form — literals, ranges, bindings, _, tuples, structures, enum and variant cases, typed patterns, none and presence — and guards.
Parameters
How arguments reach a function: read-only by-value parameters, references, default values evaluated at each call, and variadic parameters with spread.