Skip to content

Specify evaluation order of function arguments #13

@laurentlb

Description

@laurentlb

Reported by @alandonovan

This program prints each argument in the call to f as it is evaluated.

def id(x):
        print(x)
        return x

def f(*args, **kwargs):
        print(args, kwargs)

f(id(1), id(2), x=id(3), *[id(4)], y=id(5), **dict(z=id(6)))

Its results vary across all implementations:

Python2: 1 2 3 5 4 6 (*args and **kwargs evaluated last)
Python3: 1 2 4 3 5 6 (positional args evaluated before named args)
Starlark-in-Java: 1 2 3 4 5 6 (lexical order)
Starlark-in-Go: crashes (github.com/google/skylark/issues/135)

The spec currently says nothing about argument evaluation order. The Starlark-in-Java semantics are the cleanest of the three but are the most complicated and least efficient to implement in a compiler, which is why the Python compilers do what they do. The problem with the Java semantics is that it requires the compiler to generate code for a sequence of positional arguments, named arguments, an optional *args, more named arguments, and an optional **kwargs, and to provide the callee with a map of the terrain. By contrast, both of the Python approaches are simple to compile: Python2 always passes *args and *kwargs at the end, and Python3 always pushes the *args list before the first named.

One way to finesse the problem without loss of generality would be to specify Python2 semantics but to statically forbid named arguments after *args, such as y=id(5) in the example. (This mirrors the static check on the def statement, which requires that *args and **kwargs come last.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions