Skip to content

Commit

Permalink
Add keyword-only arguments to the spec (#248)
Browse files Browse the repository at this point in the history
* Add keyword-only arguments to the spec

The wording is copied from google/starlark-go#143 and google/starlark-go#151

Fixes #23

---------

Co-authored-by: Alexandre Rostovtsev <[email protected]>
  • Loading branch information
laurentlb and tetromino authored Mar 16, 2023
1 parent e2175b4 commit ce1fdb0
Showing 1 changed file with 51 additions and 6 deletions.
57 changes: 51 additions & 6 deletions spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -1199,8 +1199,8 @@ f(x=2, y=1, z=3) # (2, 1, {"z": 3})
It is a static error if any two parameters of a function have the same name.

Just as a function definition may accept an arbitrary number of
positional or keyword arguments, a function call may provide an
arbitrary number of positional or keyword arguments supplied by a
positional or named arguments, a function call may provide an
arbitrary number of positional or named arguments supplied by a
list or dictionary:

```python
Expand Down Expand Up @@ -1231,7 +1231,10 @@ Function arguments are evaluated in the order they appear in the call.

Unlike Python, Starlark does not allow more than one `*args` argument in a
call, and if a `*args` argument is present it must appear after all
positional and named arguments.
positional and named arguments. In particular, even though keyword-only
arguments ([see below](#function-definitions)) are declared after `*args` in a
function's definition, they nevertheless must appear before `*args` in a call
to the function.

A function call completes normally after the execution of either a
`return` statement, or of the last statement in the function body.
Expand Down Expand Up @@ -2688,7 +2691,7 @@ the parameter list (which is enclosed in parentheses), a colon, and
then an indented block of statements which form the body of the function.

The parameter list is a comma-separated list whose elements are of
four kinds. First come zero or more required parameters, which are
several kinds. First come zero or more required parameters, which are
simple identifiers; all calls must provide an argument value for these parameters.

The required parameters are followed by zero or more optional
Expand All @@ -2699,11 +2702,47 @@ provide an argument value for it.
The required parameters are optionally followed by a single parameter
name preceded by a `*`. This is the called the _varargs_ parameter,
and it accumulates surplus positional arguments specified by a call.
It is conventionally named `*args`.

The varargs parameter may be followed by zero or more
parameters, again of the forms `name` or `name=expression`,
but these parameters differ from earlier ones in that they are
_keyword-only_: if a call provides their values, it must do so as
keyword arguments, not positional ones.

Note that even though keyword-only arguments are declared after `*args` in a
function's definition, they nevertheless must appear before `*args` in a call
to the function.

```python
def g(a, *args, b=2, c):
print(a, b, c, args)

g(1, 3) # error: function g missing 1 argument (c)
g(1, *[4, 5], c=3) # error: keyword argument c may not follow *args
g(1, 4, c=3) # "1 2 3 (4,)"
g(1, c=3, *[4, 5]) # "1 2 3 (4, 5)"
```

A non-variadic function may also declare keyword-only parameters,
by using a bare `*` in place of the `*args` parameter.
This form does not declare a parameter but marks the boundary
between the earlier parameters and the keyword-only parameters.
This form must be followed by at least one optional parameter.

```python
def f(a, *, b=2, c):
print(a, b, c)

f(1) # error: function f missing 1 argument (c)
f(1, 3) # error: function f accepts 1 positional argument (2 given)
f(1, c=3) # "1 2 3"
```

Finally, there may be an optional parameter name preceded by `**`.
This is called the _keyword arguments_ parameter, and accumulates in a
dictionary any surplus `name=value` arguments that do not match a
prior parameter.
prior parameter. It is conventionally named `**kwargs`.

Here are some example parameter lists:

Expand All @@ -2714,6 +2753,7 @@ def f(a, b, c=1): pass
def f(a, b, c=1, *args): pass
def f(a, b, c=1, *args, **kwargs): pass
def f(**kwargs): pass
def f(a, b, c=1, *, d=1): pass
```

Execution of a `def` statement creates a new function object. The
Expand Down Expand Up @@ -4195,7 +4235,12 @@ DefStmt = 'def' identifier '(' [Parameters [',']] ')' ':' Suite .
Parameters = Parameter {',' Parameter}.
Parameter = identifier | identifier '=' Test | '*' identifier | '**' identifier .
Parameter = identifier
| identifier '=' Test
| '*'
| '*' identifier
| '**' identifier
.
IfStmt = 'if' Test ':' Suite {'elif' Test ':' Suite} ['else' ':' Suite] .
Expand Down

0 comments on commit ce1fdb0

Please sign in to comment.