gvanrossum / patma

Pattern Matching
1.02k stars 64 forks source link

Should we use 'case' or 'as'? #27

Open gvanrossum opened 4 years ago

gvanrossum commented 4 years ago

We've been using case, like this:

match target:
    case Point(x, y):
        ...
    case Rectangle(x0, y0, x1, y1):
        ...

@ilevkivskyi proposes as, like this:

match target:
    as Point(x, y):
        ...
    as Rectangle(x0, y0, x1, y1):
        ...

Let's decide.

viridia commented 4 years ago

At first I was going to write a post saying that I didn't care one way or another (which seems like a waste of space, except to point out that there are valid arguments either way, and they are all aesthetic or pedagogical in nature), however I'm starting to lean towards favoring 'as'.

My reasoning is this: in the one-off form (which I support), match A as B: reads more naturally than match A case B:. And the full match statement should be consistent with the one-off form.

Also: reserved word frugality :)

gvanrossum commented 4 years ago

That makes sense, as far as it goes.

I do observe that for people proposing random new bits of syntax, as is just about the most commonly proposed keyword. It's been proposed for argument types (instead of :), return types (instead of ->), the walrus (f() as a instead of a := f()).

Also, the the three existing uses (import ... as x, with ... as x, except ... as x) all assign something to x, whereas here... Oh, wait! At least the simplest form, as x: actually does that too. But as Point(x, y) is still a bit of a stretch.

viridia commented 4 years ago

Well, in Python the keyword as traditionally functions as a way to make a statement act like an expression; I suspect that the various random pieces of syntax being suggested are trying to leverage that concept.

However, the keyword as means something different in C#: it's a type cast. a as Type is equivalent to the C++ cast operator (with runtime type checking). The use of as in the proposed match statement seems somewhat closer to this meaning.

In English, the word 'as' has multiple definitions, but I suspect the one most relevant is the prepositional one, meaning "used to refer to the function or character that someone or something has".

If I were not constrained by Python syntax and tradition, I wouldn't use a keyword at all, I'd use an operator: pattern => body or some such. However, to be consistent with other Python statements a colon has to introduce the suite. (Putting an operator in prefix position, in place of the as, for example => pattern: body, doesn't look great to me but YMMV.)

Technically you don't need a keyword at all: pattern: body is unambiguous enough in the context of match statement body. However, I don't recommend this approach either - while your PEG parser may not have a problem with it, the average reader needs a bit more syntactical clues to be able to flash-recognize a statement pattern.

I imagine that whatever syntax gets chosen, VSCode will have a very lovely syntax coloring for it.

In any case, I don't have a strong opinion about this, I'll let others weigh in.

gvanrossum commented 4 years ago

Well, in Python the keyword ‘as’ traditionally functions as a way to make a statement act like an expression;

Huh?

viridia commented 4 years ago

Sorry if I wasn't clear. As you point out, 'as' is typically used to assign to some variable. (Although import binds to a variable in either case, 'as' just changes the name of it). And when I say 'like an expression' I mean that the statement produces an output value, as opposed to merely changing control flow or having side effects, which would be the case for 'with' without the 'as' clause for example.

I guess what I am trying to say is that I agree with your characterization of the usage of the word 'as' in existing syntax, and I suspect that people who want to use 'as' in new syntax are using it in a similar way.

Tobias-Kohn commented 4 years ago

as and case convey two different ways of looking at pattern matching, quite like @viridia's comment on the one-off form already indicates.

In ML languages, it is completely natural to write things like

let Point(x, y) = p in ...

to assign p's fields to the variables x and y, respectively. Pattern matching is then an extension with the possibility to choose the most appropriate assignment out of many. In this context, as makes perfect sense.

More on the ALGOL side (i.e. C, Pascal, etc.), there is no such assignment and the primary focus is on choosing an alternative. Naturally, case is the favoured keyword there.

I still maintain that most users of Python's pattern matching will come from the ALGOL side, and despite all our nice observations how we could replace isinstance-checks with pattern matching, the great public will probably welcome it as a "switch on steroids" and primarily replace if-elif-chains by the new pattern matching.

The one argument that really speaks in favour of as is not having to introduce a new keyword. But since case as keyword really appears in very well defined, selected places, this might less of an issue than we think.

Hence, I would favour case, but I am open to as as well. And I actually do not see a problem in combing using case for general patterns and as in the one-off case. It might even be an advantage to use different keywords there.

gvanrossum commented 4 years ago

Python (like me) comes definitely from the Algol side (-60 and -68).

Once we have the machinery for a context keyword, 'match', adding 'case' is trivial.

ilevkivskyi commented 4 years ago

It is interesting that I see choice aspect more important than assignment aspect (as I mentioned in other issue), yet as still sounds better to me. Maybe this is personal, since I read it like "if I can match ... as ...". But if you are sure that using case will highlight the importance of choice aspect, I am fine with case.

viridia commented 4 years ago

I feel the same way. If it were me, I would choose 'as', but I don't think the choice matters all that much.

gvanrossum commented 4 years ago

I am strongly in favor of tradition -- case has a venerable history, from C switch to Scala match. Using as sounds a bit like a syntax hack (of which Python has plenty). But ultimate it's just bikeshedding.

viridia commented 4 years ago

For the sake of completeness (i.e. being pedantic), I'll lay out all the other options besides 'as' and 'case' even though I am not seriously proposing them:

1) Pick a different English preposition, here's a list: https://dictionary.cambridge.org/us/grammar/british-grammar/prepositions

So for example 'match to', 'match on', 'match when', etc.

2) Use an operator rather than a keyword:

match target:
    => Point(x, y):
        ...
    => Rectangle(x0, y0, x1, y1):
        ...

3) Use nothing:

match target:
    Point(x, y):
        ...
    Rectangle(x0, y0, x1, y1):
        ...
gvanrossum commented 4 years ago

We decided to go with case. The PEP needs updating.

viridia commented 4 years ago

The PEP has been updated, let's relabel this.