diff --git a/docs/design/README.md b/docs/design/README.md index f3e43873e02c..3a7d9d325842 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -1313,7 +1313,7 @@ fn Positive(a: i64) -> auto { > References: > > - [Type inference](type_inference.md) -> - [Function return clause](functions.md#return-clause) +> - [Function return specification](functions.md#return-specification) > - Proposal > [#826: Function return type inference](https://github.com/carbon-language/carbon-lang/pull/826) diff --git a/docs/design/expressions/README.md b/docs/design/expressions/README.md index 5e687f0ef34b..76f95eba3ea0 100644 --- a/docs/design/expressions/README.md +++ b/docs/design/expressions/README.md @@ -376,6 +376,8 @@ These operators act like unary postfix operators for purposes of precedence: again puts them in parentheses that clearly separate them for precedence purposes. +The operand or result of a suffix operator is called a _suffix expression_. + ## Conversions and casts When an expression appears in a context in which an expression of a specific diff --git a/docs/design/expressions/member_access.md b/docs/design/expressions/member_access.md index 04942b406f39..a686486c5ba2 100644 --- a/docs/design/expressions/member_access.md +++ b/docs/design/expressions/member_access.md @@ -1018,8 +1018,10 @@ fn Use(a: A) { } ``` -Member access has lower precedence than primary expressions, and higher -precedence than all other expression forms. +Member access has [lower precedence](README.md#precedence) than primary +expressions (literals, unqualified names, and expressions in parentheses, as in +[C++](https://cppreference.com/cpp/language/expressions#Primary_expressions)), +and higher precedence than all other expression forms. ``` // ✅ OK, `*` has lower precedence than `.`. Same as `(A.B)*`. diff --git a/docs/design/functions.md b/docs/design/functions.md index f9fe4600323c..eaf984eba795 100644 --- a/docs/design/functions.md +++ b/docs/design/functions.md @@ -12,10 +12,20 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Overview](#overview) - [Function definitions](#function-definitions) - - [Return clause](#return-clause) + - [Function signatures](#function-signatures) + - [Captures and function fields](#captures-and-function-fields) + - [Positional Parameters](#positional-parameters) + - [Return specification](#return-specification) + - [Unused parameters](#unused-parameters) - [`return` statements](#return-statements) -- [Function declarations](#function-declarations) +- [Forward declarations](#forward-declarations) + - [Redeclaration matching](#redeclaration-matching) +- [Function types and values](#function-types-and-values) + - [Bound methods](#bound-methods) - [Function calls](#function-calls) + - [Direct calls](#direct-calls) + - [Indirect calls and the `Call` interface](#indirect-calls-and-the-call-interface) + - [Overloaded call operator](#overloaded-call-operator) - [Functions in other features](#functions-in-other-features) - [Alternatives considered](#alternatives-considered) - [References](#references) @@ -24,28 +34,30 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ## Overview -> **TODO:** Update this document to reflect the introduction of function values, -> function types, and the `Call` interface in -> [#2875: Functions, function types, and function calls](/proposals/p002875-functions-function-types-and-function-calls.md). +Functions are the core building block for applications. A function definition or +declaration has one of the following syntactic forms (where items in square +brackets are optional and independent): -> **TODO:** Update this document to reflect the changes to named functions in -> [#3848: Lambdas](/proposals/p003848-lambdas.md). +- `fn` _name_ [_implicit-parameters_] [_tuple-pattern_] `=>` _expression_ `;` +- `fn` _name_ [_implicit-parameters_] [_tuple-pattern_] [`->` _return-form_] `{` + _statements_ `}` +- `fn` _name_ [_implicit-parameters_] [_tuple-pattern_] [`->` _return-form_] `;` -Functions are the core building block for applications. Carbon's basic function -syntax is: +The first form is a shorthand: `=> expression ;` is equivalent to +`-> auto { return expression; }`. When a body is present (the first and second +forms), it is a function definition. The body introduces nested scopes which may +contain local variable declarations. A function with only a signature and no +body (the third form) is a forward declaration. -- _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_ `,` _... - ]_ `)` +The syntax for parameters and returns is the same for functions and +[lambdas](lambdas.md#syntax-overview): -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. +- _implicit-parameters_: square brackets `[`...`]` enclosing default capture + modes, explicit captures, function fields, or deduced parameters, see + [lambdas](lambdas.md#implicit-parameters-in-square-brackets). +- _tuple-pattern_: parentheses `(`...`)` enclosing a list of explicit + parameter patterns, see + [pattern matching](pattern_matching.md#pattern-syntax-and-semantics). ## Function definitions @@ -57,9 +69,14 @@ fn Add(a: i64, b: i64) -> i64 { } ``` -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. +Or using the shorthand `=>` return expression syntax: + +```carbon +fn Add(a: i64, b: i64) => a + b; +``` + +These declare a function called `Add` which accepts two `i64` parameters, the +first called `a` and the second called `b`, and returns an `i64` result. C++ might declare the same thing: @@ -74,31 +91,104 @@ auto Add(std::int64_t a, std::int64_t b) -> std::int64_t { } ``` -### Return clause +### Function signatures -The return clause of a function specifies the return type using one of three -possible syntaxes: +#### Captures and function fields -- `->` 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`. +Like lambdas, named function definitions support [captures](lambdas.md#captures) +and [function fields](lambdas.md#function-fields), with these restrictions: + +- They can only be used on functions where the definition is attached to the + declaration (so they cannot be forward declared). +- Captures and function fields are only supported on local function + definitions immediately defined inside the body of another function. They + are not supported on member functions of classes/interfaces. + +#### Positional Parameters + +Like lambdas, named function definitions support +[positional parameters](lambdas.md#positional-parameters), which are used when +the explicit parameter list is omitted. Like +[captures and function fields](#captures-and-function-fields), they may only be +used with function definitions and not forward declarations. In addition, +positional parameters can only be used in a context where there is exactly one +enclosing function or lambda that has no explicit parameter list. + +#### Return specification + +The return type of a function can be specified using a return clause (`->`), or +it can be deduced using a signature return expression (`=>`). + +- `->` followed by a return form: + - Most commonly, this will be an _expression_ that directly states the + return type, such as `i64`. + - The expression will be evaluated at compile-time, so must be valid + in that context. + - For example, `fn ToString(val: i64) -> strbuf;` has a return type of + `strbuf`. + - A return form can also use `val`, `ref`, and `var` to control the + function call's expression category. For example, `-> ref i32` indicates + that the function returns by reference. See + ["Function calls and returns"](values.md#function-calls-and-returns) for + details. - `->` 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. + - Forward 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, `()`. + - The `auto` keyword may be preceded by `val`, `ref`, or `var` to specify + the return expression category. +- Omission of both `->` and `=>` 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++. +- `=>` followed by an _expression_ defines a shorthand for a function body + that returns the expression. The return type is deduced as if `-> auto` were + used. + - For example, `fn Add(a: i64, b: i64) => a + b;` has a return type of + `i64` based on the type of the expression `a + b`. + - Because the return type is deduced and not explicitly known, functions + defined using `=>` cannot have a separate forward declaration. -> **TODO:** Update this section to cover return forms, as discussed -> [here](values.md#function-calls-and-returns). +#### Unused parameters + +When a parameter introduced in a function definition is not used in the function +body, a compiler warning is issued. To suppress this warning, a parameter can be +explicitly marked as unused in one of two ways: + +- **Anonymous parameters**: By using `_` in place of the parameter name (for + example, `_: i32`). +- **`unused` parameters**: By preceding the parameter name with the `unused` + keyword (for example, `unused size: i32`), which allows preserving the + parameter name for documentation purposes. + +Both of these forms are patterns. For more details on the behavior of `unused` +name bindings and patterns, see the +[pattern matching design](pattern_matching.md#unused). + +For example: + +```carbon +// Function declaration (for example, in an API file) +fn Sum(x: List(i32), size: i32) -> i32; + +// Implementation that does not use the `size` parameter, using an +// anonymous parameter: +fn Sum(x: List(i32), _: i32) -> i32 { ... } + +// Or using the `unused` keyword to keep the name for documentation: +fn Sum(x: List(i32), unused size: i32) -> i32 { ... } +``` + +`unused` markers may only appear on definitions, not on non-defining +declarations. The names of parameters must match between redeclarations, but the +presence of the `unused` marker does not need to match, see +[redeclaration matching](#redeclaration-matching). ### `return` statements @@ -106,9 +196,9 @@ 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](#return-specification) 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 @@ -117,7 +207,7 @@ statement must have an expression that is convertible to the return type, and a > **TODO:** Update this section to cover the requirements on the form of the > expression. -## Function declarations +## Forward 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: @@ -135,29 +225,284 @@ fn Add(a: i64, b: i64) -> i64 { 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 an -implementation 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. +implementation file of the same library. -## Function calls +A function may only be forward declared once in any given file, and any forward +declaration must appear before the definition. -Function calls use a function's identifier to pass multiple expression arguments -corresponding to the function signature's parameters. For example: +To declare a function that is defined in a different library, the `extern` +modifier is used (for example, `extern fn F();`). A library that declares a +function as `extern` cannot define it. The `extern` modifier is only valid on +namespace-scoped functions, not on member functions of classes. For more details +on cross-library forward declarations and modifier merging, see the +[declaring entities design](declaring_entities.md#extern-and-extern-library). + +### Redeclaration matching + +Redeclarations of a function must match syntactically. The sequence of tokens +following the `fn` keyword (and optional scope name) up to the semicolon or open +brace must be identical. + +Specifically, the following must match exactly between the forward declaration +and the definition: + +- **Parameter names**: You cannot change a parameter name or replace it with + `_` in the definition. +- **Parameter types**: The types and grouping parentheses must match exactly. +- **Return clause**: The presence or omission of the return clause must match + exactly (for example, an omitted return type behaves equivalent to `-> ()`, + but they are syntactically different and cannot be mixed). + +The only exception is the `unused` modifier on parameters, which is allowed on a +defining declaration (such as the definition) but disallowed on a non-defining +declaration. + +Declaration modifiers (such as access control keywords or `virtual`) appear +before the `fn` keyword, so they are not involved in checking whether the two +signatures differ. + +## Function types and values + +A function declaration in Carbon introduces a new, unique, stateless type, +called a _function type_. The function name is bound to a value of that function +type. + +Distinct functions have distinct function types, even if they have the same +signature. A function type is an empty, trivial type. There is no way to name a +function type other than asking for the type of the function value. ```carbon -fn Add(a: i64, b: i64) -> i64 { - return a + b; -} +fn F(x: i32) -> i32 { return x; } -fn Run() { - Add(1, 2); +// Compile-time function. +musteval fn TypeOf[T:! type](x: T) -> type { return T; } + +// `F` is a first-class value with a first-class type. +let template FType:! type = TypeOf(F); +var my_f: FType = F; +``` + +Function values are regular values that can be stored in variables, passed to +functions, and so on. + +```carbon +fn G() -> i32 { + // `my_f` has function type `FType`. This is a direct call to `F`. + return my_f(1); } ``` -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`. +For the purpose of the [orphan rule](generics/details.md#orphan-rule), a +function type is considered to be declared by the function declaration that +introduces the function value. + +### Bound methods + +A function with a `self` parameter is a method. The type of a method is a +stateless type, like other functions. Once the method is +[bound to an instance](expressions/member_access.md#instance-binding), for +example in the expression `object.MethodName`, the result is a _bound method +value_. The type of the result is a _bound method type_, with the same signature +as the method, but with the `self` parameter removed. A bound method type +describes the callee in a method call, and a bound method value specifies the +`self` parameter of the call. + +```carbon +class HasMember { + // `HasMember.F` has a stateless function type, with signature + // `(self, n: i32) -> i32`. + fn F(self, n: i32) -> i32; +} + +fn F(h1: HasMember, h2: HasMember) -> i32 { + // `h1.F` is a bound method value whose type is a bound method type, + // with signature `(n: i32) -> i32`. + var hf: auto = h1.F; + // `h1.F` and `h2.F` are of the same bound method type. + hf = h2.F; + // Same as `h2.F(4)`. + return hf(4); +} +``` + +## Function calls + +Function calls use C-like syntax: + +> _expression_ `(` _[ expression_ `,` _expression_ `,` _... ]_ `)` + +It consists of an expression naming a callee followed by an argument list +enclosed in parentheses, which resembles a tuple of arguments. Calls take the +form `a(b, c, d)` or `a(b, c, d,)`, where: + +- `a` is the callee, which can be a name, a literal, a member access, or some + more complex expression enclosed in parentheses. +- `b`, `c`, `d` are any number of argument expressions, each optionally + prefixed with `ref` if passing to a `ref` parameter. Arguments are separated + by commas, and if the argument list is not empty, an optional trailing comma + is permitted but not required after the final argument. + +Call syntax is syntactically equivalent to a +[suffix expression](expressions/README.md#suffix-operators) followed by a tuple +literal, except that a tuple literal requires a trailing comma to form a +single-element tuple `(b,)`, whereas in call syntax both `a(b)` and `a(b,)` are +permitted. + +A _callable value_ (or _callable_ for short) is a value that can be used as the +callee of a call expression. There are several kinds of callable: + +- Functions, and more generally values of function types. +- Bound methods, such as `my_vector.Begin`. +- Lambdas. +- Parameterized entities, such as a generic class `Vector` or a generic + interface `AddWith`. +- Values of dependent types that are + [constrained to be callable](#indirect-calls-and-the-call-interface). +- User-defined class types that overload function call syntax. + +Function calls are divided into _direct calls_ and _indirect calls_. + +### Direct calls + +A call expression is a _direct call_ when the callee: + +- is the name of a parameterized entity, like a generic class or interface, or +- has a function type or bound method type. + +Note that this includes virtual method calls, even though those can include some +indirection. In a direct call, a call signature is available which is used to +check the given arguments against the callee's declared implicit and explicit +parameters. This checking proceeds as follows: + +- Argument deduction is performed by comparing the declared parameter types + against the actual argument types and deducing values for implicit arguments + that make the types equal. +- Then, for each binding in the explicit parameter list in turn, all argument + values that have been deduced are substituted into the parameter. + + - If the parameter is a `ref` parameter (other than `self`), the + corresponding argument expression at the call-site must be prefixed with + `ref`. It is a compile-time error if the call-site has a mismatched + `ref` prefix: + - An argument to a non-`ref` parameter must not be prefixed with + `ref`, and + - An argument to a `ref` parameter must be prefixed with `ref`, except + in a generic context where the parameter's `ref` status may vary. + - If the parameter is a `template :!` binding, the argument expression is + converted to have the same type as the binding and template constant + expression phase. + - If the parameter is a symbolic `:!` binding, the argument expression is + converted to have the same type as the binding and symbolic constant + expression phase. + - Otherwise, the parameter is pattern-matched against the argument. + + If a parameter is a `:!` binding, its corresponding converted argument + expression is evaluated, and its value is added to the list of deduced + argument values before any later parameters are processed. + +The result of the call expression depends on the callee: + +- If the callee is a parameterized entity such as a generic class or a generic + interface, the result is the specific instance of that generic, such as a + class or interface, and the call is a value expression of type `type`. +- If the callee has a function type, the call is an expression whose form is + the substituted return form of its signature. When evaluated, the call + expression will invoke the function and produce whatever result it returns. +- If the callee has a bound method type, it behaves the same as a function + value, except that the `self` parameter of the called function is bound to + the `self` value in the bound method value. + +### Indirect calls and the `Call` interface + +A generic parameter can be constrained to be a callable type using the `Call` +interface: + +```carbon +interface Call(... each Arg: type) { + let Result:! type; + fn Op(self, ... each arg: each Arg) -> Result; +} +``` + +A call expression that is not a direct call is an _indirect call_. It is +translated into an invocation of `Call(Arg1, Arg2,` ... `ArgN).Op`, where +`Arg1`, `Arg2`, ... `ArgN` are the types of the call's arguments in order. So +`F(arg1, arg2)` is translated into `F.(Call(Arg1, Arg2).Op)(arg1, arg2)`. + +For example, given: + +```carbon +fn Sort[T:! type, F:! Call(T, T) where .Result = Ordering] + (ref v: Vector(T), cmp: F) { + // ... + auto ord: auto = cmp(v[i], v[j]); + // ... +} +``` + +The call `cmp(v[i], v[j])` is translated into: + +```carbon + auto ord: auto = cmp.(Call(T, T).Op)(v[i], v[j]); +``` + +A function type or bound method type implements the `Call` interface for every +set of runtime argument types that a direct call to the function or bound method +would accept. The behavior of `Call.Op` is to call the function or bound method +with the provided argument list. + +Implicit conversions are permitted for parameters whose types do not involve +deduced parameters. The intent is for the `impl` to support indirect calls in +the same cases where the function supports direct calls, with the same meaning. + +```carbon +fn TakeI32Fn[F:! Call(i32)](f: F); +fn I64Fn(n: i64); +fn Run() { + // ✅ `I64Fn` can be called with an `i32`, because + // `i32 impls ImplicitAs(i64)`. + TakeI32Fn(I64Fn); +} +``` + +> **Future work:** The `Call` interface currently only supports value parameters +> and initializing returns. It is future work to remove this restriction. + +### Overloaded call operator + +The `Call` interface can be implemented to overload the meaning of the function +call operator for a type. + +```carbon +class Func(Arg:! type) { + impl as Call((Arg,)) where .Result = () { + fn Op(self, arg: (Arg,)) { Print("hello, world"); } + } +} + +fn Run() { + let f: Func(i32) = {}; + // ✅ Prints "hello, world". + f(42); +} +``` + +There are no constraints on the callee type, beyond the normal constraints for +implementing an interface. + +```carbon +class X { var n: i32; } + +impl {.a: X} as Call(()) where .Result = i32 { + fn Op(self, args: ()) -> i32 { + return self.a.n; + } +} +fn Run() -> i32 { + // Returns 1. + return {.a = {.n = 1} as X}(); +} +``` ## Functions in other features @@ -174,6 +519,8 @@ Other designs build upon basic function syntax to add advanced features: - [Only allow `auto` return types if parameters are compile-time](/proposals/p000826-function-return-type-inference.md#only-allow-auto-return-types-if-parameters-are-generic) - [Provide alternate function syntax for concise return type inference](/proposals/p000826-function-return-type-inference.md#provide-alternate-function-syntax-for-concise-return-type-inference) - [Allow separate declaration and definition](/proposals/p000826-function-return-type-inference.md#allow-separate-declaration-and-definition) +- [Signature-based function types](/proposals/p002875-functions-function-types-and-function-calls.md#signature-based-function-types) +- [Make direct and indirect calls behave uniformly](/proposals/p002875-functions-function-types-and-function-calls.md#make-direct-and-indirect-calls-behave-uniformly) ## References @@ -181,3 +528,15 @@ Other designs build upon basic function syntax to add advanced features: [#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) +- Proposal + [#2022: Unused Pattern Bindings (Unused Function Parameters)](https://github.com/carbon-language/carbon-lang/pull/2022) +- Proposal + [#2875: Functions, function types, and function calls](https://github.com/carbon-language/carbon-lang/pull/2875) +- Proposal + [#3762: Merging forward declarations](https://github.com/carbon-language/carbon-lang/pull/3762) +- Proposal + [#3763: Matching redeclarations](https://github.com/carbon-language/carbon-lang/pull/3763) +- Proposal + [#3848: Lambdas](https://github.com/carbon-language/carbon-lang/pull/3848) +- Proposal + [#5434: `ref` parameters, arguments, returns and `val` returns](https://github.com/carbon-language/carbon-lang/pull/5434) diff --git a/docs/design/lambdas.md b/docs/design/lambdas.md index 172a149430a0..3977aebbb35c 100644 --- a/docs/design/lambdas.md +++ b/docs/design/lambdas.md @@ -23,10 +23,11 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Captures](#captures) - [Capture modes](#capture-modes) - [Default capture mode](#default-capture-mode) -- [Function fields in lambdas](#function-fields-in-lambdas) +- [Function fields](#function-fields) - [Copy semantics](#copy-semantics) - [Self and recursion](#self-and-recursion) - [Alternatives considered](#alternatives-considered) +- [References](#references) @@ -66,8 +67,8 @@ PushBack(my_list, fn -> T { return T.Make() }); ### Return type There are three options for how a lambda expresses its return type, parallel to -[how function declarations express returns](functions.md#return-clause): using a -return expression, using an explicit return type, or having no return. +[how function declarations express returns](functions.md#return-specification): +using a return expression, using an explicit return type, or having no return. #### Return expression @@ -124,8 +125,8 @@ Foo(fn { Print(T.Make()); }); ### Implicit parameters in square brackets -Lambdas support [captures](#captures), [fields](#function-fields-in-lambdas) and -deduced parameters in the square brackets. +Lambdas support [captures](#captures), [fields](#function-fields) and deduced +parameters in the square brackets. ```carbon fn Foo(x: i32) { @@ -215,18 +216,18 @@ To understand how the syntax between lambdas and function declarations is reasonably "continuous", refer to this table of syntactic positions and the following code examples. -| Syntactic Position | Syntax Allowed in Given Position (optional, unless otherwise stated) | -| :----------------: | :------------------------------------------------------------------------------------------------------------------: | -| A1 | Required Returned Expression ([positional parameters](#positional-parameters) allowed) | -| A2 | Required Returned Expression ([positional parameters](#positional-parameters) disallowed) | -| B | [Default capture mode](#default-capture-mode) | -| C | Explicit [Captures](#captures), [Function fields](#function-fields-in-lambdas) and Deduced Parameters (in any order) | -| D | Explicit Parameters | -| E1 | Body of Statements (no return value) ([positional parameters](#positional-parameters) allowed) | -| E2 | Body of Statements (with return value) ([positional parameters](#positional-parameters) allowed) | -| E3 | Body of Statements (no return value) ([positional parameters](#positional-parameters) disallowed) | -| E4 | Body of Statements (with return value) ([positional parameters](#positional-parameters) disallowed) | -| F | Required Return Type | +| Syntactic Position | Syntax Allowed in Given Position (optional, unless otherwise stated) | +| :----------------: | :-------------------------------------------------------------------------------------------------------: | +| A1 | Required Returned Expression ([positional parameters](#positional-parameters) allowed) | +| A2 | Required Returned Expression ([positional parameters](#positional-parameters) disallowed) | +| B | [Default capture mode](#default-capture-mode) | +| C | Explicit [Captures](#captures), [Function fields](#function-fields) and Deduced Parameters (in any order) | +| D | Explicit Parameters | +| E1 | Body of Statements (no return value) ([positional parameters](#positional-parameters) allowed) | +| E2 | Body of Statements (with return value) ([positional parameters](#positional-parameters) allowed) | +| E3 | Body of Statements (no return value) ([positional parameters](#positional-parameters) disallowed) | +| E4 | Body of Statements (with return value) ([positional parameters](#positional-parameters) disallowed) | +| F | Required Return Type | ```carbon // Lambdas (all the following are in an expression context and are @@ -260,20 +261,20 @@ fn [B, C](D) -> F { E4; } ## Positional parameters Positional parameters, denoted by a dollar sign followed by a non-negative -integer (for example, $3), are auto-typed parameters defined within the lambda's -body. +integer (for example, $3), are auto-typed parameters defined within the function +or lambda body. ```carbon let lambda: auto = fn => $0 ``` -They can be used in any lambda declaration that lacks an explicit parameter list -(parentheses). They are variadic by design, meaning an unbounded number of -arguments can be passed to any function that lacks an explicit parameter list. -Only the parameters that are named in the body will be read from, meaning the -highest named parameter denotes the minimum number of arguments required by the -function. The lambda body is free to omit lower-numbered parameters (ex: -`fn { Print($10); }`). +They can be used in any lambda or function definition that lacks an explicit +parameter list (parentheses). They are variadic by design, meaning an unbounded +number of arguments can be passed to any function that lacks an explicit +parameter list. Only the parameters that are named in the body will be read +from, meaning the highest named parameter denotes the minimum number of +arguments required by the function. The body is free to omit lower-numbered +parameters (for example, `fn { Print($10); }`). This syntax was inpsired by Swift's [Shorthand Argument Names](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/#Shorthand-Argument-Names). @@ -427,13 +428,13 @@ fn Foo2() { } ``` -## Function fields in lambdas +## Function fields -Function fields in lambdas mirror the behavior of init captures in C++. A -function field definition consists of an irrefutable pattern, `=`, and an -initializer. It matches the pattern with the initializer when the lambda -definition is evaluated. The bindings in the pattern have the same lifetime as -the function, and their scope extends to the end of the function body. +Function fields mirror the behavior of init captures in C++. A function field +definition consists of an irrefutable pattern, `=`, and an initializer. It +matches the pattern with the initializer when the function definition is +evaluated. The bindings in the pattern have the same lifetime as the function, +and their scope extends to the end of the function body. ```carbon fn Foo() { @@ -449,10 +450,11 @@ fn Foo() { ## Copy semantics -To mirror the behavior of C++, lambdas will be as copyable as their contained -function fields and function captures. This means that, if a function holds a -by-object function field, if the type of the field is copyable, so too is the -function that contains it. This also applies to captures. +To mirror the behavior of C++, lambdas and functions with captures or function +fields will be as copyable as their contained function fields and function +captures. This means that, if a function holds a by-object function field, if +the type of the field is copyable, so too is the function that contains it. This +also applies to captures. The other case is by-value function fields. Since C++ const references, when made into fields of a class, prevent the class from being copied assigned, so @@ -485,3 +487,8 @@ function fields with a `self` parameter. - [Sigil](/proposals/p003848-lambdas.md#alternative-considered-sigil) - [Additional Positional Parameter Restriction](/proposals/p003848-lambdas.md#alternative-considered-additional-positional-parameter-restriction) - [Recursive Self](/proposals/p003848-lambdas.md#alternative-considered-recursive-self) + +## References + +- Proposal + [#3848: Lambdas](https://github.com/carbon-language/carbon-lang/pull/3848) diff --git a/docs/design/variadics.md b/docs/design/variadics.md index 2cd52325e4a2..d19658d383bf 100644 --- a/docs/design/variadics.md +++ b/docs/design/variadics.md @@ -258,7 +258,7 @@ fn Min[T:! Comparable & Value](first: T, ... each next: T) -> T { ```carbon // Invokes f, with the tuple `args` as its arguments. -fn Apply[... each T:! type, F:! CallableWith(... each T)] +fn Apply[... each T:! type, F:! Call(... each T)] (f: F, args: (... each T)) -> auto { return f(...expand args); } diff --git a/proposals/p003762-merging-forward-declarations.md b/proposals/p003762-merging-forward-declarations.md index b99ecb0300ff..50223d3e10ff 100644 --- a/proposals/p003762-merging-forward-declarations.md +++ b/proposals/p003762-merging-forward-declarations.md @@ -96,7 +96,7 @@ Example rules for forward declarations in the current design: - [High-level](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/README.md#declarations-definitions-and-scopes) - [Classes](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/classes.md#forward-declaration) -- [Functions](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/functions.md#function-declarations) +- [Functions](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/functions.md#forward-declarationss) - Generics: - [`impl`](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#forward-impl-declaration) - [`interface`](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#declaring-interfaces-and-named-constraints)