Skip to content

Commit f92e0f7

Browse files
committed
Fill in a lot more about functions
1 parent dcdc6ea commit f92e0f7

File tree

1 file changed

+220
-16
lines changed

1 file changed

+220
-16
lines changed

spec/05-functions.md

Lines changed: 220 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ the time of evaluating the call expression, these steps happen:
2222
_arguments_.
2323
* The `call` method of the invocation protocol is invoked, with an array of
2424
the arguments.
25-
* Parameter binding happens, explained in section 5.8. If successful,
26-
this results in an extended environment.
25+
* Parameter binding happens, explained in section 5.7 "Parameter binding".
26+
If successful, this results in an extended environment.
2727
* The function's body is run in the extended environment. This is explained
28-
in section 5.9 "Function body".
28+
in section 5.8 "Function body".
2929
* Eventually, control might return normally, in which case a value is also
3030
returned. This value is then the value of entire call expression. This is
3131
explained in section 5.10 "Returning from a function".
@@ -44,36 +44,229 @@ see [Chapter 12: Macros](12-macros.md).
4444

4545
## 5.2 Optional parameters
4646

47-
xxx `@optional` syntax
47+
A parameter is _required_ by default, but there are two different ways to
48+
declare it _optional_, meaning that a call to the function will still succeed
49+
even if the parameter is not passed.
4850

49-
xxx `?` syntax
51+
A parameter can be declared optional using the `@optional` annotation:
52+
53+
```
54+
func fnWithOptParam(@optional param) {
55+
say param;
56+
}
57+
58+
fnWithOptParam(42); // 42
59+
fnWithOptParam(); // none
60+
61+
func fnWithReqParam(param) {
62+
say param;
63+
}
64+
65+
fnWithReqParam(42); // 42
66+
fnWithReqParam(); // <error: too few arguments>
67+
```
68+
69+
Or it can be declared optional using the `?` suffix on parameters:
70+
71+
```
72+
func fnWithOptParam(param?) {
73+
say param;
74+
}
75+
76+
fnWithOptParam(42); // 42
77+
fnWithOptParam(); // none
78+
```
79+
80+
Using both forms at once is valid but redundant, and might be flagged by a code
81+
linter:
82+
83+
```
84+
func fnWithOptParam(@optional param?) {
85+
say param;
86+
}
87+
88+
fnWithOptParam(42); // 42
89+
fnWithOptParam(); // none
90+
```
91+
92+
In a function declaration with both required and optional parameters, all the
93+
optional parameters must be declared after all the required ones.
5094

5195
## 5.3 Parameter defaults
5296

53-
xxx `@default(expr)` syntax
97+
_Parameter defaults_ are expressions that are evaluated if (and only if) an
98+
argument was not passed. There are two different ways to declare a parameter
99+
default.
100+
101+
The first way uses an annotation:
102+
103+
```
104+
func fnWithParamDefault(@default(5) param) {
105+
say param;
106+
}
107+
108+
fnWithParamDefault(42); // 42
109+
fmWithParamDefault(); // 5
110+
```
111+
112+
The second way uses an infix `=` syntax:
113+
114+
```
115+
func fnWithParamDefault(param = 5) {
116+
say param;
117+
}
118+
119+
fnWithParamDefault(42); // 42
120+
fmWithParamDefault(); // 5
121+
```
122+
123+
Using both syntaxes for the same parameter results in a declaration-time error:
124+
125+
```
126+
func fnWithParamDefault(@default(1) param = 2) { // <error: two defaults>
127+
say param;
128+
}
129+
```
130+
131+
Giving a parameter a default implies that the parameter is optional. Declaring
132+
a parameter both optional and having a default is allowed, but the default is
133+
enough.
134+
135+
```
136+
func fnWithOptionalParamWithDefault(@optional @default(1) param) { // fine
137+
}
138+
139+
func fnWithOptionalParamWithDefault(@default(2) param?) { // fine
140+
}
141+
142+
func fnWithOptionalParamWithDefault(@optional param = 3) { // fine
143+
}
144+
145+
func fnWithOptionalParamWithDefault(param? = 4) { // fine
146+
}
147+
```
148+
149+
Because the parameter name itself indicates the point at which the parameter
150+
is declared and thus visible, one difference between the annotation form and
151+
the `=` form is that the parameter itself is bound and visible in the `=` form
152+
but not in the annotation form:
54153

55-
xxx `=` syntax
154+
```
155+
func fnUsingParamInDefault(x = x) { // fine
156+
}
157+
158+
func fnUsingParamInDefault(@default(x) x) { // <error: no such variable x>
159+
}
160+
```
56161

57162
## 5.4 Rest parameter
58163

59-
xxx `@rest` syntax
164+
A function can handle an excess of arguments being passed by declaring a _rest
165+
parameter_, which will bind to an array containing the excess arguments. There
166+
are two syntaxes for declaring a rest parameter.
167+
168+
The first syntax uses a `@rest` annotation:
169+
170+
```
171+
func fnWithRestParam(x, y, z, @rest r) {
172+
say r;
173+
}
174+
175+
fnWithRestParam(1, 2, 3); // []
176+
fnWithRestParam(1, 2, 3, 4, 5); // [4, 5]
177+
```
178+
179+
The second syntax uses a prefix `...` on the parameter:
180+
181+
```
182+
func fnWithRestParam(x, y, z, ...r) {
183+
say r;
184+
}
60185
61-
xxx `...` syntax
186+
fnWithRestParam(1, 2, 3); // []
187+
fnWithRestParam(1, 2, 3, 4, 5); // [4, 5]
188+
```
189+
190+
Using both forms at once is valid but redundant, and might be flagged by a code
191+
linter:
192+
193+
```
194+
func fnWithRestParam(x, y, z, @rest ...r) {
195+
say r;
196+
}
197+
198+
fnWithRestParam(1, 2, 3); // []
199+
fnWithRestParam(1, 2, 3, 4, 5); // [4, 5]
200+
```
201+
202+
A parameter which is not a rest parameter is called an _individual_ parameter.
62203

63204
## 5.5 Named parameter
64205

65-
xxx `@named` syntax
206+
A _named_ parameter indicates that the corresponding operand should be written
207+
as a key/value pair, using the same syntax as for dictionary key/value pairs:
208+
209+
```
210+
func fnWithNamedParameter(@named param) {
211+
say param;
212+
}
213+
214+
fnWithNamedParameter(param => "hi"); // hi
215+
fnWithNamedParameter("hi"); // <error: missing named param "param">
216+
```
217+
218+
There is only one syntax for declaring named parameters: the above `@named`
219+
annotation syntax.
220+
221+
A parameter which is not named is called _positional_, as it is identified by
222+
its position in the list of parameters.
223+
224+
In a function declaration with both positional and named parameters, all the
225+
named parameters must be declared after all the positional ones.
226+
227+
By default, a named parameter is required, but it can be used together with the
228+
`@optional` annotation (or the `?` syntax) to make it an optional named
229+
parameter.
230+
231+
Similarly, a named parameter can be given a default, using either the
232+
`@default` annotation, or the `=` syntax.
66233

67234
## 5.6 Named rest parameter
68235

69-
xxx it's a combination of `@named` and `@rest` (in any order)
236+
A named parameter which is also declared as a rest parameter is a _named rest
237+
parameter_: it collects up any named arguments that were passed but don't have
238+
a corresponding argument into a dictionary of excess named arguments.
239+
240+
```
241+
func fnWithNamedRestArgument(
242+
@named x,
243+
@named @rest rest, // @rest @named also works
244+
) {
245+
say rest;
246+
}
70247
71-
xxx or `@named` and `...`
248+
fnWithNamedRestArgument(x => 1, y => 2); // { y => 2 }
249+
fnWithNamedRestArgument(x => 1); // {}
250+
```
72251

73-
## 5.8 Parameter binding
252+
Any syntax for declaring the parameter a rest parameter works:
253+
254+
```
255+
func fnWithNamedRestArgument(
256+
@named x,
257+
@named ...rest,
258+
) {
259+
say rest;
260+
}
261+
262+
fnWithNamedRestArgument(x => 1, y => 2); // { y => 2 }
263+
fnWithNamedRestArgument(x => 1); // {}
264+
```
265+
266+
## 5.7 Parameter binding
74267

75268
During function invocation, when arguments have been passed to a function for
76-
invocation, and before the function body can run, an environment is constructed in which to run the function body.
269+
invocation, and before the function body can run, an environment is constructed in which the function body later runs.
77270

78271
This happens in two steps: first, making sure that there is an argument for
79272
each required parameter and a parameter for each passed argument, and second,
@@ -115,7 +308,18 @@ passed that rest parameters weren't present to absorb.
115308
The resulting environment is the one that will be used when running the
116309
function body.
117310

118-
## 5.9 Function body
311+
## 5.8 Function body
312+
313+
The function body runs normally, except that the environment it runs in is
314+
extended with the parameters bound to either arguments or parameter defaults.
315+
316+
Inside a function body, it is also valid to use the statement `return <expr>;`
317+
which has the effect of evaluating `<expr>` and immediately terminating the
318+
running of the function body, returning the value that results to the caller.
319+
320+
## 5.9 Returning from a function
119321

120-
## 5.10 Returning from a function
322+
A value is returned from the function, either by explicitly executing a
323+
`return` statement in the function body, or by "falling off the end" of the
324+
function. In the latter case, the value returned from the function is `none`.
121325

0 commit comments

Comments
 (0)