Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #69556 > unrolled thread

Re: Yet Another Switch-Case Syntax Proposal

Started byChris Angelico <rosuav@gmail.com>
First post2014-04-03 08:50 +1100
Last post2014-04-03 00:50 -0600
Articles 3 — 3 participants

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Yet Another Switch-Case Syntax Proposal Chris Angelico <rosuav@gmail.com> - 2014-04-03 08:50 +1100
    Re: Yet Another Switch-Case Syntax Proposal Steven D'Aprano <steve@pearwood.info> - 2014-04-03 01:06 +0000
      Re: Yet Another Switch-Case Syntax Proposal Ian Kelly <ian.g.kelly@gmail.com> - 2014-04-03 00:50 -0600

#69556 — Re: Yet Another Switch-Case Syntax Proposal

FromChris Angelico <rosuav@gmail.com>
Date2014-04-03 08:50 +1100
SubjectRe: Yet Another Switch-Case Syntax Proposal
Message-ID<mailman.8822.1396475455.18130.python-list@python.org>
On Thu, Apr 3, 2014 at 1:53 AM, Lucas Malor <3kywjyds5d@snkmail.com> wrote:
> For example, in a "switch x" statement, the code "case iterable: " is identical to "if x in iterable: " (or elif etc). So if you want to perform the same case block for more than one value, you have only to specify a tuple, a range etc.
> I would suggest to add an exception for non-iterable variables, so that you don't have to write "case var, : " but simply "case var: " and it will be identical to "if x == var: ". It's a bit tricky but the alternative is ugly.
>

This is sounding like a nasty special case. I'm ambivalent on the
overall proposal (want to see some real-world usage examples and how
they read), but I don't like the "iterable vs non-iterable"
distinction. Compare:

case 1,2,3: # Tuple - checks for any of its members
case range(10,110,10): # Range object - beautiful, convenient!
case 42: # Non-iterable, works the way you'd expect
case {1:"Test",2:"Hello",3:[]}: # Dictionary, may be surprising
case "Test",: # Tuple with a single string in it - works but ugly
case "Test": # And there's your problem.

You now have three valid ways to interpret that last statement:
1) It matches the exact string "Test", the way people will expect
2) It matches any of the results of iterating over it
3) It matches anything where x in "Test" is true

The first option is a big fat special case, and one that'll get more
complicated as you start looking at subclasses and such. The second
means that "case x" is equivalent to "case tuple(x)", but I can't
imagine people would actually want that in real usage. The third is
the way you've described it so far, but again, I cannot imagine it as
anything other than highly surprising that my last statement above
will match "st" and "es".

It would be more invasive to the language, but possibly better, to
have a new magic method __case__ which gets called to see if this
object matches this switched object. If that isn't defined, an
equality check is done. Then all of the above cases can be made
unsurprising by simply defining __case__ on a tuple (membership test)
and a range (ditto, except that the members aren't specifically
instantiated); everything else will check equality. (Having a dict
check for its keys is surprising, IMO, and I don't mind that one not
working.) It'd make it a *lot* easier to ensure sane behaviour in
custom classes; if you want your class to function like a single unit,
don't define __case__, but if you want it to function like a
collection, set __case__=__in__. What do you reckon?

ChrisA

[toc] | [next] | [standalone]


#69561

FromSteven D'Aprano <steve@pearwood.info>
Date2014-04-03 01:06 +0000
Message-ID<533cb3fd$0$2909$c3e8da3$76491128@news.astraweb.com>
In reply to#69556
On Thu, 03 Apr 2014 08:50:47 +1100, Chris Angelico wrote:

> On Thu, Apr 3, 2014 at 1:53 AM, Lucas Malor <3kywjyds5d@snkmail.com>
> wrote:
>> For example, in a "switch x" statement, the code "case iterable: " is
>> identical to "if x in iterable: " (or elif etc). So if you want to
>> perform the same case block for more than one value, you have only to
>> specify a tuple, a range etc. I would suggest to add an exception for
>> non-iterable variables, so that you don't have to write "case var, : "
>> but simply "case var: " and it will be identical to "if x == var: ".
>> It's a bit tricky but the alternative is ugly.
>>
>>
> This is sounding like a nasty special case. I'm ambivalent on the
> overall proposal (want to see some real-world usage examples and how
> they read), but I don't like the "iterable vs non-iterable" distinction.

If we're going to add "switch" and "case" keywords, how about we also add 
"of"? Then we can write:

switch x case of a, b, c:
    # x equals one of a, b or c
case of d, e, f:
    # x equals one of d, e or f
case in g, h, i:
    # g, h and i must be iterable, and x is in one of them
else:
    # none of the above match


That means we can cleanly match the common use-case where we want to 
match something by equality, comparing against a list of 1 or more 
(usually) scalar values:

case of 1, 2, [23, 42], 99:
    assert x == 1 or x == 2 or x = [23,42] or x == 99

while also supporting the more complex case where we're matching against 
one or more sequences:

case in (1, 2, 99), [23, 42]:
    assert x == 1 or x == 2 or x = 99 or x == 23 or x == 42


Of course, in practice the second case is likely to be given dynamically, 
not as literals:

case in LIST_OF_KEYWORDS:
    ...


Another option is to say that the cases being tested ought to be quite 
small in number. If you're trying to do this:

case in range(100000000):
    ...

you're doing it wrong. That being the case, we only need to match by 
equality:

case 1, 2, 3:
    assert x == 1 or x == 2 or x == 3

and can write this when we want to match against a sequence or iterator:

case *LIST_OF_KEYWORDS:
    ...


and on the rare occasion we want to match against substrings, we can 
build a wrapper class:

class Wrapper:
    def __init__(self, value):
        self.value = value
    def __eq__(self, other):
        return other in self.value

case Wrapper("Hello world!"):
    # matches if x is a substring of "Hello world!"



But what's the advantage here? Since Python is not a static-typed 
language, it's unlikely that there are any compile-time optimizations 
that can be performed here. If there are any run-time optimizations that 
a JIT optimizing compiler like Python can perform, it probably can 
perform them just as well on a series of if...elif. So I'm not sure I see 
what having special syntax for a switch-case statement gives us.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#69570

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-04-03 00:50 -0600
Message-ID<mailman.8826.1396507894.18130.python-list@python.org>
In reply to#69561
On Wed, Apr 2, 2014 at 7:06 PM, Steven D'Aprano <steve@pearwood.info> wrote:
> If we're going to add "switch" and "case" keywords, how about we also add
> "of"? Then we can write:
>
> switch x case of a, b, c:
>     # x equals one of a, b or c
> case of d, e, f:
>     # x equals one of d, e or f
> case in g, h, i:
>     # g, h and i must be iterable, and x is in one of them
> else:
>     # none of the above match

I don't think I like the idea of having "case in" and "case of"
meaning two different things, particularly since the one that you have
labeled with "of" is the one that I think should use "in" and vice
versa.  Seems like too much potential for confusion here.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web