# Functions
## Overview
A function is defined by writing a function signature after the `:` and a statement (expression or `{` `}` compound statement) after the `=`. After the optional [template parameters](declarations.md#template-parameters) available for all declarations, a function signature consists of a possibly-empty [parameter list](#parameters), and one or more optional [return values](#return-values).
For example, the minimal function named `func` that takes no parameters and returns nothing (`#!cpp void`) is:
``` cpp title="A minimal function"
func: ( /* no parameters */ ) = { /* empty body */ }
```
##
Function signatures: Parameters, returns, and using function types
###
Overview
There are six kinds of function parameters, and two of them are the kinds of functions returns:
| Kind | Parameter | Return |
| -------- | -------- | ------- |
| `in` | ⭐ | |
| `inout` | ✅ | |
| `out` | ✅ | |
| `copy` | ✅ | |
| `move` | ✅ | ✅ |
| `forward` | ✅ | ⭐ |
The two cases marked ⭐ can automatically pass/return by value or by reference, and so they can be optionally written with `_ref` to require pass/return by reference and not by value (i.e., `in_ref`, `-> forward_ref`).
That's it. For details, see below.
###
Parameters
The parameter list is a [list](common.md#lists) enclosed by `(` `)` parentheses. Each parameter is declared using the [same unified syntax](declarations.md) as used for all declarations. For example:
``` cpp title="Declaring parameters" hl_lines="2-4"
func: (
x: i32, // parameter x is a 32-bit int
y: std::string, // parameter y is a std::string
z: std::map // parameter z is a std::map
)
= {
// ...
}
```
The parameter type can be deduced by writing `_` (the default, so it can be omitted). You can use `is` to declare a type constraint (e.g., a concept) that a deduced type must match, in which case `_` is required. For example:
``` cpp title="Declaring a parameter of constrained deduced type" hl_lines="2 3 6"
// ordinary generic function, x's type is deduced
print: (x: _) = { std::cout void`.
#### Single anonymous return values
**`#!cpp ->` _kind_ `X`** to return a single unnamed value of type `X` using the same kinds as in the [parameters](#parameters) syntax, but where the only legal kinds are `move` (the default) or `forward` (with optional `forward_ref`; see below). The type can be `#!cpp -> void` to signify the function has no return value. If `X` is not `#!cpp void`, the function body must have a `#!cpp return /*value*/;` statement that returns a value of type `X` on every path that exits the function, or must be a single expression of type `X`.
To deduce the return type, write `_`:
- `-> _` deduces by-value return.
- `-> forward _` deduces by-value return (if the function returns a prvalue or type member object) or by-reference return (everything else), based on the `decltype` of the returned expression.
- `-> forward_ref _` deduces by-reference return only.
A function whose body is a single expression `= expr;` defaults to `-> forward _ = { return expr; }`.
For example:
``` cpp title="Functions with an unnamed return value" hl_lines="2 4 7 9 12 14 15 18 20 22"
// A function returning no value (void)
increment_in_place: (inout a: i32) -> void = { a++; }
// Or, using syntactic defaults, the following has identical meaning:
increment_in_place: (inout a: i32) = { a++; }
// A function returning a single value of type i32
add_one: (a: i32) -> i32 = { return a+1; }
// Or, using syntactic defaults, the following has identical meaning:
add_one: (a: i32) -> i32 = a+1;
// A generic function returning a single value of deduced type
add: (a:T, b:U) -> forward _ = { return a+b; }
// Or, using syntactic defaults, the following have identical meaning:
add: (a, b) -> forward _ = a+b;
add: (a, b) a+b;
// A generic function expression returning a single value of deduced type
vec.std::ranges::sort( :(x:_, y:_) -> forward _ = { return y (quotient: int, remainder: int) = {
if divisor == 0 {
quotient = 0; // constructs quotient
remainder = 0; // constructs remainder
}
else {
quotient = dividend / divisor; // constructs quotient
remainder = dividend % divisor; // constructs remainder
}
}
main: () = {
div := divide(11, 5);
std::cout (where: iterator, inserted: bool) = {
set_returned := container.insert(value);
where = set_returned.first;
inserted = set_returned.second;
}
ssize: (this) -> i64 = std::ssize(container);
// ...
}
use_inserted_position: (_) = { }
main: () = {
m: set = ();
ret := m.insert("xyzzy");
if ret.inserted {
use_inserted_position( ret.where );
}
assert( m.ssize() == 1 );
}
```
####
Function outputs are not implicitly discardable
A function's outputs are its return values, and the "out" state of any `out` and `inout` parameters.
Function outputs cannot be silently discarded. To explicitly discard a function output, assign it to `_`. For example:
``` cpp title="No silent discard" hl_lines="9 11 13 17-18 23-24 29-30"
f: () -> void = { }
g: () -> int = { return 10; }
h: (inout x: int) -> void = { x = 20; }
main: ()
= {
f(); // ok, no return value
std::cout _ = default for functions that return something"
equals: (a, b) = a == b;
```
Finally, at expression scope (aka "lambda/temporary") functions/objects aren't named, and the trailing `;` is optional:
``` cpp title="(not) 'equals': Identical meaning, but without a name as an unnamed function at expression scope"
:(a, b) = a == b
```
Here are some additional examples of unnamed function expressions:
``` cpp title="Some more examples of unnamed function expressions"
std::ranges::for_each( a, :(x) = std::cout Note: Cpp2 doesn't have a separate "lambda" syntax; you just use the regular function syntax at expression scope to write an unnamed function, and the syntactic defaults are chosen to make such function expressions convenient to write. And because in Cpp2 every local variable [capture](expressions.md#captures) (for example, `waldo$` above) is written in the body, it doesn't affect the function syntax.