|
|
@@ -10,54 +10,161 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
|
|
## Table of contents
|
|
|
|
|
|
-- [TODO](#todo)
|
|
|
-- [Basic functions](#basic-functions)
|
|
|
+- [Overview](#overview)
|
|
|
+- [Function definitions](#function-definitions)
|
|
|
+ - [Return clause](#return-clause)
|
|
|
+ - [`return` statements](#return-statements)
|
|
|
+- [Function declarations](#function-declarations)
|
|
|
+- [Function calls](#function-calls)
|
|
|
+- [Functions in other features](#functions-in-other-features)
|
|
|
+- [Alternatives considered](#alternatives-considered)
|
|
|
+- [References](#references)
|
|
|
|
|
|
<!-- tocstop -->
|
|
|
|
|
|
-## TODO
|
|
|
+## Overview
|
|
|
|
|
|
-This is a skeletal design, added to support [the overview](README.md). It should
|
|
|
-not be treated as accepted by the core team; rather, it is a placeholder until
|
|
|
-we have more time to examine this detail. Please feel welcome to rewrite and
|
|
|
-update as appropriate.
|
|
|
+Functions are the core building block for applications. Carbon's basic function
|
|
|
+syntax is:
|
|
|
|
|
|
-## Basic functions
|
|
|
+- _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_ `,` _...
|
|
|
+ ]_ `)`
|
|
|
|
|
|
-Programs written in Carbon, much like those written in other languages, are
|
|
|
-primarily divided up into "functions" (or "procedures", "subroutines", or
|
|
|
-"subprograms"). These are the core unit of behavior for the programming
|
|
|
-language. Let's look at a simple example to understand how these work:
|
|
|
+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:
|
|
|
+
|
|
|
+```carbon
|
|
|
+fn Add(a: i64, b: i64) -> i64 {
|
|
|
+ return a + b;
|
|
|
+}
|
|
|
```
|
|
|
-fn Sum(a: Int, b: Int) -> Int;
|
|
|
+
|
|
|
+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:
|
|
|
+
|
|
|
+```cpp
|
|
|
+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;
|
|
|
+}
|
|
|
```
|
|
|
|
|
|
-This declares a function called `Sum` which accepts two `Int` parameters, the
|
|
|
-first called `a` and the second called `b`, and returns an `Int` result. C++
|
|
|
-might declare the same thing:
|
|
|
+### Return clause
|
|
|
+
|
|
|
+The return clause of a function specifies the return type using one of three
|
|
|
+possible syntaxes:
|
|
|
+
|
|
|
+- `->` followed by an _expression_, such as `i64`, 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 of
|
|
|
+ `String`.
|
|
|
+- `->` followed by the `auto` keyword indicates that
|
|
|
+ [type inference](type_inference.md) should be used to determine the return
|
|
|
+ type.
|
|
|
+ - For example, `fn Echo(val: i64) -> auto { return val; }` will have a
|
|
|
+ return type of `i64` through type inference.
|
|
|
+ - Declarations must have a known return type, so `auto` is not valid.
|
|
|
+ - The function must have precisely one `return` statement. That `return`
|
|
|
+ statement's expression will then be used for type inference.
|
|
|
+- Omission indicates that the return type is the empty tuple, `()`.
|
|
|
+ - For example, `fn Sleep(seconds: i64);` is similar to
|
|
|
+ `fn Sleep(seconds: i64) -> ();`.
|
|
|
+ - `()` is similar to a `void` return type in C++.
|
|
|
+
|
|
|
+### `return` statements
|
|
|
+
|
|
|
+The [`return` statement](control_flow/return.md) is essential to function
|
|
|
+control flow. It ends the flow of the function and returns execution to the
|
|
|
+caller.
|
|
|
+
|
|
|
+When the [return clause](#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:
|
|
|
+
|
|
|
+```carbon
|
|
|
+// Declaration:
|
|
|
+fn Add(a: i64, b: i64) -> i64;
|
|
|
+
|
|
|
+// Definition:
|
|
|
+fn Add(a: i64, b: i64) -> i64 {
|
|
|
+ return a + b;
|
|
|
+}
|
|
|
```
|
|
|
-std::int64_t Sum(std::int64_t a, std::int64_t b);
|
|
|
|
|
|
-// Or with trailing return type syntax:
|
|
|
-auto Sum(std::int64_t a, std::int64_t b) -> std::int64_t;
|
|
|
+The corresponding definition may be provided later in the same file or, when the
|
|
|
+declaration is in an
|
|
|
+[`api` file of a library](code_and_name_organization/#libraries), in the `impl`
|
|
|
+file of the same library. The signature of a function declaration must match the
|
|
|
+corresponding definition. This includes the [return clause](#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:
|
|
|
+
|
|
|
+```carbon
|
|
|
+fn Add(a: i64, b: i64) -> i64 {
|
|
|
+ return a + b;
|
|
|
+}
|
|
|
+
|
|
|
+fn Main() {
|
|
|
+ Add(1, 2);
|
|
|
+}
|
|
|
```
|
|
|
|
|
|
-Let's look at how some specific parts of this work. The function declaration is
|
|
|
-introduced with a keyword `fn` followed by the name of the function `Sum`. This
|
|
|
-declares that name in the surrounding scope and opens up a new scope for this
|
|
|
-function. We declare the first parameter as `Int a`. The `Int` part is an
|
|
|
-expression (here referring to a constant) that computes the type of the
|
|
|
-parameter. The `:` marks the end of the type expression and introduces the
|
|
|
-identifier for the parameter, `a`. The parameter names are introduced into the
|
|
|
-function's scope and can be referenced immediately after they are introduced.
|
|
|
-The return type is indicated with `-> Int`, where again `Int` is just an
|
|
|
-expression computing the desired type. The return type can be completely omitted
|
|
|
-in the case of functions which do not return a value.
|
|
|
-
|
|
|
-Calling functions involves a new form of expression: `Sum(1, 2)` for example.
|
|
|
-The first part, `Sum`, is an expression referring to the name of the function.
|
|
|
-The second part, `(1, 2)` is a parenthesized list of arguments to the function.
|
|
|
-The juxtaposition of one expression with parentheses forms the core of a call
|
|
|
-expression, similar to a postfix operator.
|
|
|
+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](generics/overview.md#generic-functions) adds support for
|
|
|
+ deduced parameters and generic type parameters.
|
|
|
+- [Class member functions](classes.md#member-functions) adds support for
|
|
|
+ methods and class functions.
|
|
|
+
|
|
|
+## Alternatives considered
|
|
|
+
|
|
|
+- [Function keyword](/proposals/p0438.md#function-keyword)
|
|
|
+- [Only allow `auto` return types if parameters are generic](/proposals/p0826.md#only-allow-auto-return-types-if-parameters-are-generic)
|
|
|
+- [Provide alternate function syntax for concise return type inference](/proposals/p0826.md#provide-alternate-function-syntax-for-concise-return-type-inference)
|
|
|
+- [Allow separate declaration and definition](/proposals/p0826.md#allow-separate-declaration-and-definition)
|
|
|
+
|
|
|
+## References
|
|
|
+
|
|
|
+- Proposal
|
|
|
+ [#438: Add statement syntax for function declarations](https://github.com/carbon-language/carbon-lang/pull/438)
|
|
|
+- Proposal
|
|
|
+ [#826: Function return type inference](https://github.com/carbon-language/carbon-lang/pull/826)
|