Skip to content
This repository has been archived by the owner on Nov 21, 2022. It is now read-only.

Bring 'else' back? #89

Open
gvanrossum opened this issue Jun 24, 2020 · 29 comments
Open

Bring 'else' back? #89

gvanrossum opened this issue Jun 24, 2020 · 29 comments
Labels
fully pepped Issues that have been fully documented in the PEP rejected A rejected idea

Comments

@gvanrossum
Copy link
Owner

There were several commenters on today's revealing of the PEP on python-dev who want an else clause instead of case _: to enter final catch-all block. It's not terrible. If we do this I propose it should be indented with the case clauses:

match t:
    case P1():
        ...
    case P2():
        ...
    else:
        ...

I'm trying to hold this off a little longer, but it may be an easy thing to give.

@gvanrossum gvanrossum added the open Still under discussion label Jun 24, 2020
@brandtbucher
Copy link
Collaborator

brandtbucher commented Jun 24, 2020

I can see the arguments for else, but for me it personally comes down to "preferably only one way to do it".

case _ is already a more flexible way to do it: unlike else, it can be guarded and reordered. It feels wrong to add the less powerful, duplicate else simply for completeness' sake.

Also, lets not forget that disallowing else is a two-way door.

@brandtbucher
Copy link
Collaborator

Also, ambiguity about the "correct" indentation level for else is another big strike against it, in my opinion.

@0312birdzhang
Copy link

I prefer default like Java,C++,JavaScript and Php.

@Delta456
Copy link
Contributor

else is better for semantics. default is more for switch.

@Tobias-Kohn
Copy link
Collaborator

@0312birdzhang: I think at this point we should strive for a discussion on arguments rather than personal preferences, so as to effectively move forward with this.

First, I agree with @Delta456 in that default belongs into a switch-statement, which is not really what we are proposing here. Second, the two proposals on the table (else vs. case _) both extend existing syntax (in the case of case _ syntax that would come into existence because of the PEP, of course), whereas default is something else entirely without any connection to the rest of the proposal.

@Delta456
Copy link
Contributor

If we really want case _ then the behavior of _ should be like Go's. If it cannot be like that then else is better suited.

@Tobias-Kohn
Copy link
Collaborator

I totally agree with @brandtbucher and feel he summarised the main arguments quite neatly.

The only argument I can see that really is in favour of else is that basically everything in Python also has an else clause (but, to be perfectly honest, this is something I really dislike as there is IMHO no natural or obvious way to connect a for-loop, say, with an else—but that's a different discussion that has taken place long ago). Hence, it might feel strange for experienced Python programmers not to have an else here.

If we were to bring else back than I am still convinced it would have to attach to match and not the case, i.e.:

match t:
    case P1():
        ...
else:
    ...

I see another argument in favour of case _:, though. Basically, we cannot outlaw case _: in a sensible way. After all, I could just write case x: and not use the value assigned to x, or case x | [x]:, etc. In other words: we are going to have case _: any way. This means that the discussion is actually about whether we want to allow else too, rather than instead of.

I am wondering whether the idea of having an else might be connected to the question of whether to raise if a value does not match any pattern... (issue #5)

@Tobias-Kohn
Copy link
Collaborator

@Delta456 Could you briefly explain what you mean by behaviour like Go's? Not everyone here is familiar with Go.

@Delta456
Copy link
Contributor

See this

@viridia
Copy link
Collaborator

viridia commented Jun 24, 2020

What specific aspect of Go's behavior are you referring to?

Given that the underscore is already a valid name in Python, and there is an established convention of using it for values we want to ignore (such as in tuple unpacking), we can't radically alter the definition of it without breaking a lot of programs.

@Delta456
Copy link
Contributor

Delta456 commented Jun 24, 2020

I am refering that _ cannot be used anywhere in the program. If it does then it will raise an error.

I know that so I think we should go with else.

@elimisteve
Copy link

As @Delta456 alluded to, _ is a valid identifier in Python. This seems to bring ambiguity to the semantics of case _ when _ is a defined, in-scope variable. This is not uncommon and is even the recommended way to implement internationalization support in Django and elsewhere:

from django.utils.translation import ugettext as _

else is quite clear semantically but agree that the ambiguity of indentation level being unfortunate.

Right now my vote is for else, with default as a reasonable alternative.

@gvanrossum
Copy link
Owner Author

@Delta456 and @elimisteve, ‘_’ is used as a wildcard in the rest of the pattern matching syntax, ‘case _’ is just a special use of that. Read the README.md in this repo.

@Tobias-Kohn
Copy link
Collaborator

It seems like the discussion here is more and more circling about a different issue. Instead of discussing case _ vs. else, it is more about the semantics of _ and whether it should be a wildcard/throwaway (e.g., cf. issue #73).

The issue at hand is much rather whether we want/need an else, given that the pattern matching itself already supports a catch-all case. Depending on the micro-syntax of choice, the latter might then be written as case _:, case x:, case ...:, case *:, case:, or whatever.

I see no reason, however, to bring in default as an alternative here! We already have two perfectly good alternatives, which would both naturally extend what we already have. We are not, however, looking for yet another alternative out of the blue and with no precedent in either this PEP or Python. In the end, default would just introduce yet another keyword for a case that is already covered otherwise.

@Delta456
Copy link
Contributor

Delta456 commented Jun 24, 2020

It seems like the discussion here is more and more circling about a different issue. Instead of discussing case _ vs. else, it is more about the semantics of _ and whether it should be a wildcard/throwaway (e.g., cf. issue #73).

Yes

In the end, default would just introduce yet another keyword for a case that is already covered otherwise.

Yes

I want to conclude that else will be better suited and it is more readable also _ has no importance other than wildcards. This topic of wildcards should be taken at #92.

@gvanrossum
Copy link
Owner Author

This really would be easier if we could agree on how to indent else!

I really think it should be aligned with 'case' (similar to how people indent 'default' in C switches); I believe only @Tobias-Kohn disagrees. But since it really is just a catch-all case, I think it should align with the cases -- otherwise people might wonder that it has some other semantics (given that try and for/while have somewhat, um, interesting semantics for else.

@brandtbucher
Copy link
Collaborator

brandtbucher commented Jun 24, 2020

If we're adding it for completeness alone, then it should "obviously" match the other compound statements and be at that outer level. But I agree that, logically, it is a case, and should be indented with those... but why disguise a case as else in the first place? I still feel like we're entering a one-way door for no real benefit.

Eh, I've said all I have to say.

@thautwarm
Copy link

FYI, some points in favor of adding "else":

  1. A lot of programming languages hold else/otherwise even though they have wildcard pattern _, for example, Ruby, which is sometimes regarded as the "counterpart" of Python.

  2. Every compound control flow statement has an else. If no else for match, a good intuition might be ruined for newbies. Keeping consistent brings simplicity and understandability.

@Delta456
Copy link
Contributor

for/while only have else case when it exists the loop. As they have it. How about allowing else in both places i.e. :

match t:
        case P1():
        case P2():
         ...
        case P3():
        else: # it will go to else when none of the cases match
else: # after completion of match

This can hopefully solve the problem as @brandtbucher says for for/while.

@gvanrossum
Copy link
Owner Author

@Delta456 you are a true Solomon.

@Delta456
Copy link
Contributor

Delta456 commented Jun 25, 2020

@gvanrossum lol! Its an honor!

@Tobias-Kohn
Copy link
Collaborator

Having given it some thought, I still believe that the else should match the identation level of match rather than case, sorry 😉. I understand the idea why it should be on the same level as case. However, in that case, it is really just an alias for case _: and nothing else. On the level of match, it feels more like closure to me in that the match-statement as a whole has an else-clause for what happens if no case clause matched the expression.

To put it differently, the way I think of it might be expressed roughly as:

try: # match
    case A:
        ...
    case B:
        ...
except NoMatch:
    # this is the else-clause

I would not seriously consider allowing it on both level as suggested by @Delta456, and having slightly different semantics makes it even worse. The mental burdon is just way too high.

@thautwarm
Copy link

thautwarm commented Jun 25, 2020

Many including me said

Every compound control flow statement has an else.

From this perspective, +1 @Tobias-Kohn

@Delta456
Copy link
Contributor

Delta456 commented Jun 26, 2020

@Tobias-Kohn I know why you disagree but we need an else clause on the case level too. But imagine if we will have a try and expect then it leaves the purpose of match IMHO. We can make it optional on both levels perhaps? I think this debate will go for a long time.

Every compound control flow statement has an else

I suggested following this rule only.

@DimitrisJim
Copy link

DimitrisJim commented Jun 26, 2020

@Tobias-Kohn How would an else clause indented to the level of match play with static checkers? Considering a pattern that isn't exhausted both case _ and else: would seem to satisfy it.

Every compound statement has an else when that else provides some additional behavior. I can't see how this is the case if case _ already provides the behavior needed.

@Tobias-Kohn
Copy link
Collaborator

@DimitrisJim I certainly agree with that. I am actually not advocating to have an else: in the first place as it really is already covered by case _:. My argument is more that if we were to add an else:, then it should complement the match, not the last case.

Every compound statement has an else when that else provides some additional behavior.

This is a fair and important point, nicely put (highlights from me). It also answers @Delta456's suggestion to have two possible else clauses.

@Tobias-Kohn
Copy link
Collaborator

Some while ago we had considered to have a one-off syntax, but decided to put it into the 'deferred ideas' section. Now, I absolutely do not want to reopen that discussion: the one-off syntax is an excellent candidate for the 'deferred ideas' to be considered later. However, if a future PEP proposes to include the one-off syntax, they will probably want to have an else with that—if we look at the strong votes for introducing an else even here, I don't think it is realistic to assume that the one-off variant would be accepted without one.

So, if we combine the one-off idea with an else, we find that instead of writing:

match x:
    case P: ...
else:
    ...

you could have something like:

match x as P:
    ...
else:
    ...

or, using the alternative synax:

if match x as P:
    ...
else:
    ...

Having the else attached to match rather than case would work out of the box for such a future scenario.

Let me reiterate: this is not a votum to bring the one-off syntax back on the table, but rather another argument why I feel that the else—if we end up having one—should be attached to match.


All that being said, adding else is obviously unnecessary in the first place! But should the community feel strongly that we need one, then it is not the end of the world for me.

@gvanrossum
Copy link
Owner Author

I propose that we reject this idea. The reasoning should be

  • case _: works just fine
  • There will forever be confusion(*) about the indentation level of the else:
  • "Completionist" arguments like "every other statement has one" are pretty useless (and false)

(*) Not to mention disagreement. :-)

@viridia
Copy link
Collaborator

viridia commented Jul 2, 2020

Let's add that to the PEP - one reason we didn't go with else is the difficulty of getting agreement on the level of indentation.

@gvanrossum gvanrossum added needs more pep An issue which needs to be documented in the PEP rejected A rejected idea and removed open Still under discussion labels Jul 2, 2020
@gvanrossum gvanrossum added fully pepped Issues that have been fully documented in the PEP and removed needs more pep An issue which needs to be documented in the PEP labels Jul 2, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
fully pepped Issues that have been fully documented in the PEP rejected A rejected idea
Projects
None yet
Development

No branches or pull requests

9 participants