[Python-ideas] Match statement brainstorm

Franklin? Lee leewangzhong+python at gmail.com
Wed May 25 13:09:31 EDT 2016

On Wed, May 25, 2016 at 5:26 AM, Paul Moore <p.f.moore at gmail.com> wrote:
> On 25 May 2016 at 10:04, Franklin? Lee <leewangzhong+python at gmail.com> wrote:
>> Problem: `Point(x, y, ...)` is a legitimate function call, so if
>> `Point(x, 0)` is a legal pattern (i.e. no distinguishing syntax
>> between values and bindnames), you'd need the syntax to be `Point(x,
>> y, *...)`. Personally, I'd require that everything is a bindname
>> (unless it looks like a constructor call), and require checks to be in
>> guards.
> With the above syntax, "bare" values aren't a valid match, so in a
> match, Point(x, y) can never be a function call, it must be a match
> "Object of type Point, with x and y attributes (which we check for but
> don't bind)".

I mean a function call, in particular a constructor call.

Take these examples, written as constructor destructure assignment:
        Point(x, y) = obj
        Point(x=_, y=_) = obj

I'd say that Point(x, y) binds two positional constructor arguments,
and Point(x=_, y=_) binds attributes .x and .y to throwaway variables.
(`object` takes no positional args, and I want it to start allowing
keyword args.)

Here's my proposed implementation again: Call Point.__asmatch__(obj,
nargs, keys, args, kwargs) (where "asmatch" might be an enhanced
"__getnewargs__"), with these params:
    - obj: The object to destructure, which is an instance of Point
(possibly typechecked by the match engine before calling). (Note that
we're not calling obj.__asmatch__(nargs, ...), to give superclasses a
chance to destructure a subclass instance.)
    - nargs: Number of positional args.
    - keys: Keyword args specified.
    - args: Whether or not *rest was used. (Extension: Whether or not
splat was used, and whether to discard them.)
    - kwargs: Whether or not **rest was used. (Extension: and whether
to discard them.)

It will return (args: tuple, kwargs: dict) if the match is possible.
It will check whether there are enough positional args, and whether
all keys were valid, and perform the logic about the optional params
(giving up as few args and kwargs as possible).

Contract: The returned tuple and dict _should_ be valid for
Point(*args, **kwargs). This constraint is not necessary if "discard"
was specified for anything.

My problem is, this would then be ambiguous:
        Point(0, ...) = obj    # Match if the first arg is 0 and the
second is `...`?

while this would not, but might be ugly.
        Point(0, *...) = obj

More information about the Python-ideas mailing list