You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add regular _ref option to in param and forward _ return; remove oddity inout: const
Closes#876
This keeps things nicely orthogonal addresses the two open issues with parameter passing:
- the oddity of `inout : const`, which becomes just `in_ref`
- the need to directly express both Cpp1 `-> decltype(auto)` and `-> auto&&`, which now are `-> forward _` and `-> forward_ref _`
Style Parameter Return
-------- --------- -------
`in` ⭐
`inout` ✅
`out` ✅
`copy` ✅
`move` ✅ ✅
`forward` ✅ ⭐
The two ⭐'s are the cases that automatically pass/return _by value_ or reference:
- all uses of `in`
- deduced uses of `-> forward _` (ordinary `-> forward specific_type` always returns by reference, adding constness if there's an `in this` parameter)
Now both ⭐ cases also provide a `_ref` option to not choose by-value. This addresses the two open issues with parameter passing:
An example that illustrates both is std::min:
min: (in_ref a, in_ref b) -> forward_ref _
= { if b < a { return b; } else { return a; } }
main: (args) = {
x := 456;
y := 123;
std::cout << min(x, y) << '\n';
}
The container<T>::operator[] case could already be written like this, where the first return lowers to Cpp1 `T const&` and the second to `T&`:
container: <T> type = {
buf: std::array<T, 10> = ();
operator[]: ( this, idx: i32) -> forward T = buf[idx];
operator[]: (inout this, idx: i32) -> forward T = buf[idx];
}
main: (args) = {
v: container<int> = ();
std::cout << v[0] << '\n';
}
Copy file name to clipboardExpand all lines: docs/cpp2/functions.md
+43-16Lines changed: 43 additions & 16 deletions
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,23 @@ func: ( /* no parameters */ ) = { /* empty body */ }
14
14
15
15
## <a id="function-signatures"></a> Function signatures: Parameters, returns, and using function types
16
16
17
+
### <a id="parameter-kinds"></a> Overview
18
+
19
+
There are six kinds of function parameters, and two of them are the kinds of functions returns:
20
+
21
+
| Kind | Parameter | Return |
22
+
| -------- | -------- | ------- |
23
+
| `in` | ⭐ | |
24
+
| `inout` | ✅ | |
25
+
| `out` | ✅ | |
26
+
| `copy` | ✅ | |
27
+
| `move` | ✅ | ✅ |
28
+
| `forward` | ✅ | ⭐ |
29
+
30
+
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`).
31
+
32
+
That's it. For details, see below.
33
+
17
34
### <a id="parameters"></a> Parameters
18
35
19
36
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:
There are six ways to pass parameters that cover all use cases, that can be written before the parameter name:
44
61
45
-
| Parameter***kind*** | "Pass an `x` the function ______" | Accepts arguments that are | Special semantics | ***kind*** `x: X` Compiles to Cpp1as |
62
+
| Parameter ***kind*** | "Pass an `x` the function ______" | Accepts arguments that are | Special semantics | ***kind*** `x: X` compiles to Cpp1 as |
46
63
|---|---|---|---|---|
47
-
| `in` (default) | can read from | anything | always `#!cpp const`<p>automatically passes by value if cheaply copyable| `X const x` or `X const& x` |
48
-
| `copy` | gets a copy of | anything | acts like a normal local variable initialized with the argument | `X x` |
49
-
| `inout` | can read from and write to | lvalues | | `X& x` |
50
-
| `out` | writes to (including construct) | lvalues (including uninitialized) | must `=` assign/construct before other uses | `cpp2::impl::out<X>` |
51
-
| `move` | moves from (consume the value of) | rvalues | automatically moves from every definite last use | `X&&` |
52
-
| `forward` | forwards | anything | automatically forwards from every definite last use | `T&&` constrained to type `X` |
64
+
| <big>**`in`**</big> (default) | can read from | anything | always `#!cpp const`<p>automatically passes by value if cheaply copyable<br><br>to guarantee a by-reference passing, use `in_ref` | `X const x` or <br> `X const& x` |
65
+
| <big>**`copy`**</big> | gets a copy of | anything | acts like a normal local variable initialized with the argument | `X x` |
66
+
| <big>**`inout`**</big> | can read from and write to | lvalues | | `X& x` |
67
+
| <big>**`out`**</big> | writes to (including construct) | lvalues (including uninitialized) | must `=` assign/construct before other uses | `cpp2::impl::out<X>` |
68
+
| <big>**`move`**</big> | moves from (consume the value of) | rvalues | automatically moves from every definite last use | `X&&` |
69
+
| <big>**`forward`**</big> | forwards | anything | automatically forwards from every definite last use<br><br> for a deduced type (`-> forward _`), deduces a by-reference or by-value return (the latter if the function returns an rvalue); to guarantee a by-reference return, use `-> forward_ref _` | for a specific type, `-> forward T` compiles to Cpp1 `-> T&&`, and adds `const` if the function has an `in this` parameter (Cpp1 `const` member function)<br><br> for a deduced type, `-> forward _` compiles to Cpp1 `-> decltype(auto)`, and `-> forward_ref _` compiles to Cpp1 `-> auto&&` |
53
70
54
71
> Note: All parameters and other objects in Cpp2 are `#!cpp const` by default, except for local variables. For details, see [Design note: `#!cpp const` objects by default](https://github.com/hsutter/cppfront/wiki/Design-note%3A-const-objects-by-default).
55
72
@@ -76,11 +93,19 @@ wrap_f: (
76
93
77
94
### <aid="return-values"></a> Return values
78
95
79
-
A function can return either of the following. The default is `#!cpp -> void`.
96
+
A function can return either a single anonymous return value, or a return parameter list containing named return value(s). The default is `#!cpp -> void`.
80
97
81
-
(1) **`#!cpp -> X`** to return a single unnamed value of type `X` using the same passing styles from the [parameters](#parameters) syntax, but where the only passing styles are `move` (the default) or `forward`. 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.
98
+
#### Single anonymous return values
82
99
83
-
To deduce the return type, write `-> _`. A function whose body returns a single expression `expr` can deduce the return type, and omit writing the leading `-> _ = { return` and trailing `; }`.
100
+
**`#!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`.
101
+
102
+
To deduce the return type, write `_`:
103
+
104
+
-`-> _` deduces by-value return.
105
+
-`-> forward _` deduces by-value return (if the function returns an rvalue) or by-reference return (everything else).
(2) **`#!cpp -> ( /* parameter list */ )`** to return a list of named return parameters using the same [parameters](#parameters) syntax, but where the only passing styles are `out` (the default, which moves where possible) or `forward`. The function body must [initialize](objects.md#init) the value of each return-parameter `ret` in its body the same way as any other local variable. An explicit return statement is written just `#!cpp return;` and returns the named values; the function has an implicit `#!cpp return;` at the end. If only a single return parameter is in the list, it is emitted in the lowered Cpp1 code the same way as (1) above, so its name is only available inside the function body.
**`#!cpp -> ( /* parameter list */ )`** to return a list of named return parameters using the same [parameters](#parameters) syntax, but where the only needed kinds are `out` (the default, which moves where possible) or `forward`. The function body must [initialize](objects.md#init) the value of each return-parameter `ret` in its body the same way as any other local variable. An explicit return statement is written just `#!cpp return;` and returns the named values; the function has an implicit `#!cpp return;` at the end. If only a single return parameter is in the list, it is emitted in the lowered Cpp1 code the same way as a single anonymous return value above, so its name is only available inside the function body.
113
140
114
141
For example:
115
142
@@ -256,7 +283,7 @@ else {
256
283
257
284
**`#!cpp do`** and **`#!cpp while`** are like always in C++, except that `(``)` parentheses around the condition are not required. Instead, `{``}` braces around the loop body *are* required.
258
285
259
-
**`#!cpp for range do (e)`*****statement*** says "for each element in `range`, call it `e` and perform the statement." The loop parameter `(e)` is an ordinary parameter that can be passed using any [parameter passing style](#parameters); as always, the default is `in`, which is read-only and expresses a read-only loop. The statement is not required to be enclosed in braces.
286
+
**`#!cpp for range do (e)`*****statement*** says "for each element in `range`, call it `e` and perform the statement." The loop parameter `(e)` is an ordinary parameter that can be passed using any [parameter kinds](#parameters); as always, the default is `in`, which is read-only and expresses a read-only loop. The statement is not required to be enclosed in braces.
260
287
261
288
Every loop can have a `next` clause, that is performed at the end of each loop body execution. This makes it easy to have a counter for any loop, including a range `#!cpp for` loop.
262
289
@@ -433,9 +460,9 @@ Next, `: _` is also the default parameter type, so we don't need to write even t
433
460
equals: (in a, in b) -> _ = { return a == b; }
434
461
```
435
462
436
-
Next, `in` is the default [parameter passing mode](#parameters). So we can use that default too:
463
+
Next, `in` is the default [parameter kind](#parameters). So we can use that default too:
437
464
438
-
```cpp title="equals: Identical meaning, now using the 'in' default parameter passing style"
465
+
```cpp title="equals: Identical meaning, now using the 'in' default parameter kind"
0 commit comments