Functions
Table of contents
- Overview
- Function definitions
- Function declarations
- Function calls
- Functions in other features
- Alternatives considered
- References
Overview
Functions are the core building block for applications. Carbon’s basic function syntax is:
- parameter: identifier
:
expression - parameter-list: [ parameter
,
parameter,
… ] -
return-clause: [ ->
_< expression_ auto
> ] - signature:
fn
identifier(
parameter-list)
return-clause - function-definition: signature
{
statements}
- function-declaration: signature
;
- function-call: identifier
(
[ expression,
expression,
… ])
A function with only a signature and no body is a function declaration, or forward declaration. When the body is a present, it’s a function definition. The body introduces nested scopes which may contain local variable declarations.
Function definitions
A basic function definition may look like:
fn Add(a: i64, b: i64) -> i64 {
return a + b;
}
This declares a function called Add
which accepts two i64
parameters, the first called a
and the second called b
, and returns an i64
result. It returns the result of adding the two arguments.
C++ might declare the same thing:
std::int64_t Add(std::int64_t a, std::int64_t b) {
return a + b;
}
// Or with trailing return type syntax:
auto Add(std::int64_t a, std::int64_t b) -> std::int64_t {
return a + b;
}
Return clause
The return clause of a function specifies the return type using one of three possible syntaxes:
->
followed by an expression, such asi64
, directly states the return type. This expression will be evaluated at compile-time, so must be valid in that context.- For example,
fn ToString(val: i64) -> String;
has a return type ofString
.
- For example,
->
followed by theauto
keyword indicates that type inference should be used to determine the return type.- For example,
fn Echo(val: i64) -> auto { return val; }
will have a return type ofi64
through type inference. - Declarations must have a known return type, so
auto
is not valid. - The function must have precisely one
return
statement. Thatreturn
statement’s expression will then be used for type inference.
- For example,
- Omission indicates that the return type is the empty tuple,
()
.- For example,
fn Sleep(seconds: i64);
is similar tofn Sleep(seconds: i64) -> ();
. ()
is similar to avoid
return type in C++.
- For example,
return
statements
The return
statement is essential to function control flow. It ends the flow of the function and returns execution to the caller.
When the return clause is omitted, the return
statement has no expression argument, and function control flow implicitly ends after the last statement in the function’s body as if return;
were present.
When the return clause is provided, including when it is -> ()
, the return
statement must have an expression that is convertible to the return type, and a return
statement must be used to end control flow of the function.
Function declarations
Functions may be declared separate from the definition by providing only a signature, with no body. This provides an API which may be called. For example:
// Declaration:
fn Add(a: i64, b: i64) -> i64;
// Definition:
fn Add(a: i64, b: i64) -> i64 {
return a + b;
}
The corresponding definition may be provided later in the same file or, when the declaration is in an API file of a library, in an implementation file of the same library. The signature of a function declaration must match the corresponding definition. This includes the return clause; even though an omitted return type has equivalent behavior to -> ()
, the presence or omission must match.
Function calls
Function calls use a function’s identifier to pass multiple expression arguments corresponding to the function signature’s parameters. For example:
fn Add(a: i64, b: i64) -> i64 {
return a + b;
}
fn Run() {
Add(1, 2);
}
Here, Add(1, 2)
is a function call expression. Add
refers to the function definition’s identifier. The parenthesized arguments 1
and 2
are passed to the a
and b
parameters of Add
.
Functions in other features
Other designs build upon basic function syntax to add advanced features:
- Generic functions adds support for deduced parameters and compile-time parameters.
- Class member functions adds support for methods and class functions.
Alternatives considered
- Function keyword
- Only allow
auto
return types if parameters are compile-time - Provide alternate function syntax for concise return type inference
- Allow separate declaration and definition