On Wed, May 25, 2016 at 1:52 AM, Nick Coghlan
Using the running demo:
def demo(arg): given arg: case x, y, *_: # Tuple matching (implicit name binding) ... case (.x, .y) as p, q: # Attribute matching ... case (["x"], ["y"]) as p, q: # Item matching ... case (.x) as p and isinstance(p, int): # Match + condition ... case if isinstance(arg, int): # Condition only ... else: # Default ...
The other key change there is introducing "as" to the individual cases in order to be able to separate the match pattern definition from the local name binding.
I still don't like that `case THING` is a pattern, rather than a value to test against. Here's my modifications with "as", attributes, and def demo(arg): given arg: case as x, y, *_: # Tuple matching (implicit name binding) ... case as object(x=p, y=q, **_): # Attribute matching ... case as {'x': p, 'y', q, **_}: # Item matching ... case as object(x=p, **_) and isinstance(p, int): # Match + condition ... case if isinstance(arg, int): # Condition only ... else: # Default ... Here, the "as" pattern is a shape to fit the object's parts into, and it should be possible to get back the original (or something isomorphic to it) by evaluating the pattern expression (so `case as {'x': p, 'y', q, **_}": assert isomorphic({'x': p, 'y', q, **_}, arg)`). For attribute-matching, I think it's possible to make user types also play well with this syntax for attribute matching, and I made a proposal earlier for an API. (Section 'Matching user classes' here: https://mail.python.org/pipermail/python-ideas/2016-May/040343.html) (Proposal to make the `object` case more reasonable: `object(**kwargs)` constructor creates an object with the given attributes. It won't affect subclasses, because `object.__new__` can test whether `cls is object`.) Perhaps literal dicts could match against sequences, too. {0: x, 42: y, **rest} = some_list And this could be how you enforce types: dict({0: x, 42: y, **rest}) = some_list # Fails. tuple((x, y, z)) = some_list # Fails. though I haven't figured out how these constructor shapes would be implemented for user types. Big conceptual obstacle: iterating over a dict gives its keys (which has always bothered me), so as a value, `list({0: x, 42: y, **rest})` would just be a list of keys. (I'd give up the typecheck syntax, personally, and have you move the check into a guard. I'm not too attached to the indexing syntax, either.) Note that I force an explicit `**_, so that `object(x=p)` will fail if `arg` has (non-dunder) attributes other than `x` (which I think is a good thing). It's kinda wasteful to pack unused things into a variable, so `...` could specify ignored args (which has come up before on this list), and the matcher engine can tell the type's matchmaker that it doesn't care about the other args. 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.