Re: Yet Another Switch-Case Syntax Proposal

2014-04-10 Thread Lucas Malor
On 6 April 2014 20:07, Chris Angelico rosuav-at-gmail.com 
|python-list@python.org|  wrote:
> Here's a simpler form of the proposal, which might cover what you
> need. It's basically a short-hand if/elif tree.
>
> case expression comp_op expression:
> suite
> case [comp_op] expression:
> suite
> 
> else:
> suite

I like this solution, but I tought about a simpler one. Basically it's my first 
proposal with two modifications:
1. case / elcase instead of continue, as before
2. if the case expression is a *tuple* (and not any one iterable), case suite 
is executed if the switched expression is an element of the tuple.

If you want to match exactly a tuple, you have simply to put it into another 
tuple of length 1. Tricky but too much rare to care about.
To recap:

switch_stmt ::=  "switch" expression "case" expression_list ":" suite
("case" | "elcase" expression_list ":" suite)*
["else" ":" suite]
1. if expression_list is a tuple, the case suite will be executed if the switch 
expression is a member of the tuple.
2. if expression_list is not a tuple, the case suite will be executed if the 
switch expression is equal
Example:

briefing_days = ("Tue", "Thu")
normal_days = ("Mon", "Wed", "Fri")

switch day normal_days + briefing_days:
go_to_work = True
day_type = "weekday"
case normal_days:

lunch_time = datetime.time(12)
meeting_time = datetime.time(14)
elcase briefing_days:

lunch_time = datetime.time(11, 30)
meeting_time = datetime.time(12, 30)
else:

go_to_work = False
day_type = "festive"
lunch_time = None
meeting_time =None

Another example:
switch tarot case 0:
card = "Fool"
case 1:
card = "Alan Moore"
case 2:
card = "High Priestess"
etc.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-06 Thread Chris Angelico
On Mon, Apr 7, 2014 at 6:13 AM, Michael Torrie  wrote:
> On 04/06/2014 12:07 PM, Chris Angelico wrote:
>> This has a slight oddity of parsing (in that an expression can
>> normally have a comparison in it); if you really want to use the
>> result of a comparison inside a case block, you'd have to parenthesize
>> it. But it's easy enough to explain to a human.
>
> This syntax is almost identical to the if/elif/else syntax, though, no?

Like I said, it's a short-hand for an if/elif tree, nothing more. Most
of the proposals have effectively been that anyway. There are
differences, though; the case target gets evaluated only once, for
instance. I'm not pushing strongly for its addition to the language.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-06 Thread Ian Kelly
On Sun, Apr 6, 2014 at 11:49 AM, Lucas Malor <3kywjyd...@snkmail.com> wrote:
> On 3 April 2014 20:12, Ian Kelly ian.g.kelly-at-gmail.com
> |python-list@python.org|  wrote:
>> Use this instead [of continue]:
>
>>
>> switch day case in ("Mon", "Tue", "Wed", "Thu", "Fri"):
>> go_to_work = True
>> day_type = "ferial"
>> if day in ("Tue", "Thu"):
>> lunch_time = datetime.time(11, 30)
>> meeting_time = datetime.time(12, 30)
>> else:
>> lunch_time = datetime.time(12)
>> meeting_time = datetime.time(14)
>> case in ("Sat", "Sun"):
>> go_to_work = False
>> day_type = "festive"
>>
>> You get an extra level of indentation this way, but it reads less like
>> spaghetti code.
>
>
> Well, if you have to add an if-else to your switch-case, it means
> switch-case syntax is not so useful.

I agree; the above is better suited to be an if.

> An alternative is to imitate elif, so you'll have elcase. This way we don't
> need continue. Since I do not like elcasein, the best solution is to do as
> suggested by many of you, so case in instead of casein.

So if I'm understanding your intention correctly, "case" means to
check this case regardless of whether any preceding case was matched,
and "elcase" means to check this case only if the most recent "case"
and its dependent "elcases" preceding this one were not matched.

switch "Mon" case in ("Tue", "Thu"):
print(1)
elcase in ("Mon", "Wed", "Fri"):
print(2)
case in ("Sat", "Sun"):
print(3)
elcase in ("Mon", "Tue", "Wed", "Thu", "Fri"):
print(4)

will print 2 and 4, correct?

> But if you can write case in, why you can't write "case" comp_operator in
> general? With this syntax you can do also case is not, case > etc...

At this point I see no advantage in adding this syntax.  It is so
similar to an if-elif chain that surely any optimization that could be
applied would be equally possible if the if-elif syntax, so why not
just use that?
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-06 Thread Michael Torrie
On 04/06/2014 12:07 PM, Chris Angelico wrote:
> This has a slight oddity of parsing (in that an expression can
> normally have a comparison in it); if you really want to use the
> result of a comparison inside a case block, you'd have to parenthesize
> it. But it's easy enough to explain to a human.

This syntax is almost identical to the if/elif/else syntax, though, no?

> 
> case day in briefing_days:
> lunch_time = datetime.time(11, 30)
> meeting_time = datetime.time(12, 30)
> case not in briefing_days + festive_days:
> lunch_time = datetime.time(12)
> meeting_time = datetime.time(14)
> case in festive_days:
> go_to_work = False
> day_type = "festive"
> else:
> go_to_work = True
> day_type = "ferial"
> 
> A case statement that opens with a comparison operator takes the value
> from the previous case (without re-evaluating it); a case statement
> that lacks a comparison altogether assumes == and does the above. In
> either case (pardon the pun), the check will be done only if the
> preceding case was false. An 'else' clause is effectively equivalent
> to a 'case' that's always true.
> 
> Adds only one keyword to the language ("switch" is gone), and adds an
> edge case to parsing that's unlikely to come up in non-contrived code.
> 
> ChrisA
> 

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-06 Thread Chris Angelico
On Mon, Apr 7, 2014 at 3:49 AM, Marco S.  wrote:
> switch day case in briefing_days:
>
> lunch_time = datetime.time(11, 30)
> meeting_time = datetime.time(12, 30)
> case not in briefing_days + festive_days:
>
> lunch_time = datetime.time(12)
> meeting_time = datetime.time(14)
> case in festive_days:
>
> go_to_work = False
> day_type = "festive"
> else:
>
> go_to_work = True
> day_type = "ferial"
>
> The if-else equivalent will be:
>
> if day in briefing_days:
>
> lunch_time = datetime.time(11, 30)
> meeting_time = datetime.time(12, 30)
> if day not in briefing_days + festive_days:
>
> lunch_time = datetime.time(12)
> meeting_time = datetime.time(14)
> if day in festive_days:
>
> go_to_work = False
> day_type = "festive"
> else:
>
> go_to_work = True
> day_type = "ferial"

Here's a simpler form of the proposal, which might cover what you
need. It's basically a short-hand if/elif tree.

case expression comp_op expression:
suite
case [comp_op] expression:
suite
...
else:
suite

This has a slight oddity of parsing (in that an expression can
normally have a comparison in it); if you really want to use the
result of a comparison inside a case block, you'd have to parenthesize
it. But it's easy enough to explain to a human.

case day in briefing_days:
lunch_time = datetime.time(11, 30)
meeting_time = datetime.time(12, 30)
case not in briefing_days + festive_days:
lunch_time = datetime.time(12)
meeting_time = datetime.time(14)
case in festive_days:
go_to_work = False
day_type = "festive"
else:
go_to_work = True
day_type = "ferial"

A case statement that opens with a comparison operator takes the value
from the previous case (without re-evaluating it); a case statement
that lacks a comparison altogether assumes == and does the above. In
either case (pardon the pun), the check will be done only if the
preceding case was false. An 'else' clause is effectively equivalent
to a 'case' that's always true.

Adds only one keyword to the language ("switch" is gone), and adds an
edge case to parsing that's unlikely to come up in non-contrived code.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-06 Thread Marco S.
On 3 April 2014 20:12, Ian Kelly ian.g.kelly-at-gmail.com |
python-list@python.org|  wrote:
> Use this instead [of continue]:
>
> switch day case in ("Mon", "Tue", "Wed", "Thu", "Fri"):
> go_to_work = True
> day_type = "ferial"
> if day in ("Tue", "Thu"):
> lunch_time = datetime.time(11, 30)
> meeting_time = datetime.time(12, 30)
> else:
> lunch_time = datetime.time(12)
> meeting_time = datetime.time(14)
> case in ("Sat", "Sun"):
> go_to_work = False
> day_type = "festive"
>
> You get an extra level of indentation this way, but it reads less like
> spaghetti code.


Well, if you have to add an if-else to your switch-case, it means
switch-case syntax is not so useful.
An alternative is to imitate elif, so you'll have elcase. This way we don't
need continue. Since I do not like elcasein, the best solution is to do as
suggested by many of you, so case in instead of casein.
But if you can write case in, why you can't write "case" comp_operator in
general? With this syntax you can do also case is not, case > etc... Your
example will turn into

briefing_days = ("Tue", "Thu")
festive_days = ("Sat", "Sun")

switch day case in briefing_days:
lunch_time = datetime.time(11, 30)
meeting_time = datetime.time(12, 30)
case not in briefing_days + festive_days:
lunch_time = datetime.time(12)
meeting_time = datetime.time(14)
case in festive_days:
go_to_work = False
day_type = "festive"
else:
go_to_work = True
day_type = "ferial"

The if-else equivalent will be:

if day in briefing_days:
lunch_time = datetime.time(11, 30)
meeting_time = datetime.time(12, 30)
if day not in briefing_days + festive_days:
lunch_time = datetime.time(12)
meeting_time = datetime.time(14)
if day in festive_days:
go_to_work = False
day_type = "festive"
else:
go_to_work = True
day_type = "ferial"


If you don't specify comp_operator, the default is ==. Example:

switch day_num case 1:
day_str = "Monday"
elcase 2:
day_str = "Thursday"
else:
day_str = "etcetera"
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-04 Thread Ian Kelly
On Fri, Apr 4, 2014 at 10:44 AM, Marko Rauhamaa  wrote:
> Consider:
>
> switch local_sabbath():# bad
> case (1, 2, 3) as sabbath:
> ...

I'm not overly fond of that either.  That's why I liked the OP's
choice to put the first case in the switch statement.

> Now Python "framing" requires that you place something between the first
> ":" and "case":
>
> switch local_sabbath():# bad
> pass
> case (1, 2, 3) as sabbath:
> ...

That's absurd.  Granted that omitting the pass doesn't match any
existing syntax, but that doesn't mean it *must* be done that way.

> Placing the expression after the colon terminates the first colon
> cleanly. Also, the "lambda" precedent allows an expression to follow a
> colon; both "lambda" and my "switch" mandate that the expression stay on
> the same line with the colon.

But in the case of the lambda *expression*, the following expression
is effectively the entire "suite" of the lambda "clause", mirroring
the form of a def statement.  If "local_sabbath()" is treated as the
suite of the switch *statement*, then "Python framing" tells us the
same construct could be written like this:

switch:
local_sabbath()
case 1:
...

And if that's allowed, then why not this?

switch:
if username == "ozzy":
black_sabbath()
else:
local_sabbath()
case 1:
...

Or:

switch:
for sabbath in list_of_sabbaths:
sabbath
case 1:
...

Or even:

switch:
pass
case 1:
...

The intent of the first two are fairly clear, but they're way out of
scope for a switch statement.  I don't even intuitively know what to
do with the last two.  The point here is that the switch expression
really ought to be a single expression contained in the switch header,
not a suite.


>> Second, "as" clauses are used in other contexts for local assignment.
>> What is the purpose of doing that here? How does this solve the
>> problem of explicitly denoting case multiplicity?
>
> The "as" clause follows the precedent of the "try/except" statement. It
> removes the occasional annoyance in C:
>
>switch (next_char()) {
>case '\n':
>case '\r':
>putchar(???);
> :   :   :
>
> which forces you to introduce a temporary variable:

How is the target identifier of the "as" not a temporary variable?
Try/except statements and with statements use "as" keywords to capture
values that may not otherwise be available in scope for assignment.
Except assigns the exception instance that was just caught, and with
assigns whatever arbitrary object was returned by the context
manager's __enter__ method.  With switch there is no need for that;
just do this:

char = next_char()
switch next_char:
case in '\n\r':
print(char)

Similarly there is no need for the "if" or "while" statements to
support an "as" keyword, as in:

while next_char() as char:
print(char)

There are good reasons why the language generally does not allow
assignments in non-assignment statements, which is what your "as" is
trying to do.  The Pythonic way to write that loop is:

while True:
char = next_char()
if not char: break
print(char)

Which is at least as ungraceful as assigning the switch variable
before the switch statement.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-04 Thread Marko Rauhamaa
Ian Kelly :

> On Apr 4, 2014 3:51 AM, "Marko Rauhamaa"  wrote:
>>switch: local_sabbath()
>>case (1, 2, 3) as sabbath:
>>...
>>case 6:
>>...
>>else:
>>...
> [...]
>
> What's wrong with the much more natural "switch local_sabbath():"?

Consider:

switch local_sabbath():# bad
case (1, 2, 3) as sabbath:
...

Now Python "framing" requires that you place something between the first
":" and "case":

switch local_sabbath():# bad
pass
case (1, 2, 3) as sabbath:
...

Placing the expression after the colon terminates the first colon
cleanly. Also, the "lambda" precedent allows an expression to follow a
colon; both "lambda" and my "switch" mandate that the expression stay on
the same line with the colon.

> Second, "as" clauses are used in other contexts for local assignment.
> What is the purpose of doing that here? How does this solve the
> problem of explicitly denoting case multiplicity?

The "as" clause follows the precedent of the "try/except" statement. It
removes the occasional annoyance in C:

   switch (next_char()) {
   case '\n':
   case '\r':
   putchar(???);
:   :   :

which forces you to introduce a temporary variable:

   char c;
:   :   :
   c = next_char();
   switch (c) {
   case '\n':
   case '\r':
   putchar(c);
:   :   :

It is most useful in the "default"/"else" branch:

   switch: q.pop()
   case 0:
   log_direction(0)
   return 1
   case (90, 270) as angle:
   log_direction(angle)
   return 0
   case 180:
   log_direction(180)
   return -1
   else angle:
   log_direction(angle)
   return math.cos(angle * 2 * PI / 360)


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-04 Thread Devin Jeanpierre
If one were to add switch into Python, wouldn't it be desirable to
make a pattern matching switch (think the "match" or "case" construct
from Haskell or ML)? Python currently has poor support for union/sum
types in general, not just enumerations. It feels weird to add better
support for enumerations while ignoring the broader use case.

If a switch statement gets added to Python and I still need to examine
ASTs by a long chain of if-elif and isinstance and so on I will cry.

-- Devin

On Wed, Apr 2, 2014 at 7:53 AM, Lucas Malor <3kywjyd...@snkmail.com> wrote:
> Hi all. I would proposeto you all a switch-case syntax for Python. I already 
> read PEP 3103 and I'm not completely satisfied by any of the proposed 
> solutions. This is my proposal:
>
> switch_stmt ::=  "switch" identifier "case" expression_list ":" suite
> ("case" expression_list ":" suite)*
> ["else" ":" suite]
>
> or, more simply:
>
>
>
> switch x case var1:
> 
> case var2:
> ...
> case var3:
> ...
> else:
> ...
>
>
>
> Expression list should yield an iterable. The case suite will be executed if 
> the variable of the identifier is a member of the iterable.
>
> 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.
>
> Fallthrough is disabled by default. The continue keyword cause to skip all 
> the remaining current case suite. The next case will be checked. You can't 
> use the continue keyword in the else clause.
>
> Some random remarks:
> 1. switch is on the same line of the first case. This will avoid any 
> unpythonic syntaxes like:
> switch x
> case var1:
> ...
>
> or
>
> switch x:
> case var1:
> ...
>
> 2. Fallthrough is disabled by default because IMHO it's what non-programmers 
> expect and that's what programmer usually needs more. I don't think a switch 
> with such a syntax needs a break statement.
>
> 3. As an alternative, the continue statement could be written only at the end 
> of a case suite; it will be less powerful and not consistent with the other 
> compound statements, but it will improve readability.
>
> 4. I decided to not use already existing keyword like "if" or "in", since it 
> will be misleading and problematic for syntax highlighters.
>
>
> Tell me what you think about.
> --
> https://mail.python.org/mailman/listinfo/python-list
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-04 Thread Ian Kelly
On Apr 4, 2014 3:51 AM, "Marko Rauhamaa"  wrote:
>
> >>> switch day casein ("Monday", "Thursday", "Wednesday", "Tuesday",
> >>> "Friday"):
> >>>  gotowork = True
> >>>  continue
> >>> casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
> >>>  daytype = "ferial"
> >>> casein ("Saturday", "Sunday")
> >>>  daytype = "festive"
>
> That "casein" next to "switch" bugs me. Did I already propose:
>
>switch: local_sabbath()
>case (1, 2, 3) as sabbath:
>...
>case 6:
>...
>else:
>...

I don't get what this is intended to do. First, why is the expression in
the first line after the colon? That doesn't match any existing block
syntax (as you note it matches lambda, but that's an expression-level
syntax). What's wrong with the much more natural "switch local_sabbath():"?

Second, "as" clauses are used in other contexts for local assignment. What
is the purpose of doing that here? How does this solve the problem of
explicitly denoting case multiplicity?
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-04 Thread Marko Rauhamaa

 Instead of disabling fallthrough by default, why not disable it all
 together?
>>>
>>> I was tempted but there are cases in which it's useful. An example

No, it is never useful, it never was. It came into being by accident, a
design bug turned into an advertised feature.

>>> switch day casein ("Monday", "Thursday", "Wednesday", "Tuesday",
>>> "Friday"):
>>>  gotowork = True
>>>  continue
>>> casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
>>>  daytype = "ferial"
>>> casein ("Saturday", "Sunday")
>>>  daytype = "festive"

That "casein" next to "switch" bugs me. Did I already propose:

   switch: local_sabbath()
   case (1, 2, 3) as sabbath:
   ...
   case 6:
   ...
   else:
   ...

The key is to look at precedents:

   try:
...
   except (E1, E2) as e:
...
   except ...:
...
   finally:
...

and:

   lambda: expression


The "switch: day" format is a hybrid of the "try" and "lambda" syntaxes
and would be compatible with existing Python editors as well as general
Python sensibilities.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-04 Thread Steven D'Aprano
On Thu, 03 Apr 2014 11:23:39 -0700, Ethan Furman wrote:

> On 04/03/2014 09:02 AM, Lucas Malor wrote:
>>
>> In reply to Ian Kelly:
>>>
>>> Instead of disabling fallthrough by default, why not disable it all
>>> together?
>>
>> I was tempted but there are cases in which it's useful. An example
>>
>> switch day casein ("Monday", "Thursday", "Wednesday", "Tuesday",
>> "Friday"):
>>  gotowork = True
>>  continue
>> casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
>>  daytype = "ferial"
>> casein ("Saturday", "Sunday")
>>  daytype = "festive"
> 
> 
> Absolutely not.  Currently, the 'continue' key word means "stop
> processing and go back to the beginning".  

It does not go back to the beginning. That would require resetting the 
iterable, which may be impossible. And if you succeeded, it would mean a 
loop with continue might never terminate!

for i in (1, 2, 3):
print(i)
if i == 2: continue

=> prints:
1
2
1
2
1
2
1
...


Perhaps you mean "continue from the top"? But top and bottom is just an 
artifact of how we write the loop. The only direction that matters is 
iteration order, and I'm not aware of any language that allows for-loop 
iteration to go forward and backwards.

"continue" means "continue with the next iteration", as the documentation 
says:

https://docs.python.org/3/reference/simple_stmts.html

In some languages, it's even spelled "next", e.g. Perl. (After a decade 
plus of reading and writing Python code, I still try to write "next" when 
I mean continue.)  It's not a big stretch to go from "continue with the 
next iteration" to "continue with the next case".


> You would have it mean "keep
> going forward".  Thus 'continue' would mean both "go backwards" and "go
> forwards" and would lead to unnecessary confusion.

Well, there's certainly already some confusion :-)


-- 
Steven D'Aprano
http://import-that.dreamwidth.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-04 Thread Steven D'Aprano
On Thu, 03 Apr 2014 15:11:38 -0400, Terry Reedy wrote:

> On 4/3/2014 12:02 PM, Lucas Malor wrote:
> 
>>> A more suitable place to propose this would be the python-ideas
>>> mailing list.
>>
>> You're right. I posted here because this list was linked by PEP 1. But
>> now that I read more there's also python-ideas listed. Let me know if I
>> have to continue there instead.
> 
> Given that the idea has been posted to python-ideas and rejected, more
> that once I believe, I think this was the right place to post this to
> have variations discussed in a friendly manner.

I agree with Terry. Nothing wrong with gathering some feedback here first.



-- 
Steven D'Aprano
http://import-that.dreamwidth.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Chris Angelico
On Fri, Apr 4, 2014 at 2:13 PM, Ethan Furman  wrote:
> On 04/03/2014 08:09 PM, Chris Angelico wrote:
>>
>> On Fri, Apr 4, 2014 at 1:04 PM, MRAB  wrote:
>>>
>>> I thought [continue] went to the end of the loop, but because it's a
>>> loop, it
>>> just wraps around back to the top...
>>
>>
>> It goes to the bottom of the loop, and then the loop condition may or
>> may not send it to the top of the loop.
>
>
> *ahem*
>
> The loop condition is *at* the top of the loop;  if it was at the bottom it
> would be a do..until.  ;)

Well, if you go by the disassembly, Python does put the condition at
the top of the loop. But I've seen plenty of C compilers that invert
that - before the top of the loop it jumps down to the bottom, the
bottom has the condition, and the condition may or may not jump you up
to the top of the loop.

Semantics :)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Ethan Furman

On 04/03/2014 08:09 PM, Chris Angelico wrote:

On Fri, Apr 4, 2014 at 1:04 PM, MRAB  wrote:

I thought [continue] went to the end of the loop, but because it's a loop, it
just wraps around back to the top...


It goes to the bottom of the loop, and then the loop condition may or
may not send it to the top of the loop.


*ahem*

The loop condition is *at* the top of the loop;  if it was at the bottom it 
would be a do..until.  ;)

--
~Ethan~
--
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Chris Angelico
On Fri, Apr 4, 2014 at 1:04 PM, MRAB  wrote:
> I thought [continue] went to the end of the loop, but because it's a loop, it
> just wraps around back to the top...

It goes to the bottom of the loop, and then the loop condition may or
may not send it to the top of the loop.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Ethan Furman

On 04/03/2014 07:04 PM, MRAB wrote:

On 2014-04-03 19:23, Ethan Furman wrote:

On 04/03/2014 09:02 AM, Lucas Malor wrote:


In reply to Ian Kelly:


Instead of disabling fallthrough by default, why not disable it all together?


I was tempted but there are cases in which it's useful. An example

switch day casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
 gotowork = True
 continue
casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
 daytype = "ferial"
casein ("Saturday", "Sunday")
 daytype = "festive"



Absolutely not.  Currently, the 'continue' key word means "stop processing and go 
back to the beginning".  You would
have it mean "keep going forward".  Thus 'continue' would mean both "go backwards" and 
"go forwards" and would lead to
unnecessary confusion.


I thought it went to the end of the loop, but because it's a loop, it
just wraps around back to the top...


*sigh*  I see you are already confused.  ;)

H I think that would be more like 'skip' as in 'skip to the end'...

Either way, though, 'continue' would mean two very different things:

 - skip everything between here and the end of the loop

 - don't skip everything between here and the end of the case

--
~Ethan~
--
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread MRAB

On 2014-04-03 19:23, Ethan Furman wrote:

On 04/03/2014 09:02 AM, Lucas Malor wrote:


In reply to Ian Kelly:


Instead of disabling fallthrough by default, why not disable it all together?


I was tempted but there are cases in which it's useful. An example

switch day casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
 gotowork = True
 continue
casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
 daytype = "ferial"
casein ("Saturday", "Sunday")
 daytype = "festive"



Absolutely not.  Currently, the 'continue' key word means "stop processing and go 
back to the beginning".  You would
have it mean "keep going forward".  Thus 'continue' would mean both "go backwards" and 
"go forwards" and would lead to
unnecessary confusion.


I thought it went to the end of the loop, but because it's a loop, it
just wraps around back to the top...
--
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Chris Angelico
On Fri, Apr 4, 2014 at 10:03 AM, Mark Lawrence  wrote:
> Please don't take this personally, but there's more chance of me being the
> first ever World President than of anybody getting a switch/case statement
> past the BDFL.

The language in PEP 3103 (written by Guido) doesn't suggest this to
me. But maybe that's just being diplomatic.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Mark Lawrence

On 02/04/2014 15:53, Lucas Malor wrote:

Hi all. I would proposeto you all a switch-case syntax for Python. I already 
read PEP 3103 and I'm not completely satisfied by any of the proposed 
solutions. This is my proposal:

switch_stmt ::=  "switch" identifier "case" expression_list ":" suite
 ("case" expression_list ":" suite)*
 ["else" ":" suite]

or, more simply:



switch x case var1:
 
case var2:
 ...
case var3:
 ...
else:
 ...



Please don't take this personally, but there's more chance of me being 
the first ever World President than of anybody getting a switch/case 
statement past the BDFL.


--
My fellow Pythonistas, ask not what our language can do for you, ask 
what you can do for our language.


Mark Lawrence

---
This email is free from viruses and malware because avast! Antivirus protection 
is active.
http://www.avast.com


--
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Chris Angelico
On Fri, Apr 4, 2014 at 5:12 AM, Ian Kelly  wrote:
> Use this instead:
>
> switch day case in ("Mon", "Tue", "Wed", "Thu", "Fri"):
> go_to_work = True
> day_type = "ferial"
> if day in ("Tue", "Thu"):
> lunch_time = datetime.time(11, 30)
> meeting_time = datetime.time(12, 30)
> else:
> lunch_time = datetime.time(12)
> meeting_time = datetime.time(14)
> case in ("Sat", "Sun"):
> go_to_work = False
> day_type = "festive"
>
> You get an extra level of indentation this way, but it reads less like
> spaghetti code.

Still not an ideal demonstration of fall-through. Here's a much more
useful form:

switch get("version") case 0:
commands_to_get_to_version_1
case 1:
commands_to_get_to_version_2
case 2:
commands_to_get_to_version_3

# Version 3 is current.
set("version", 3)
case 3:
break
else:
raise UnknownVersionError("Unexpected version!")

With fall-through, you don't need a loop around that. You jump to the
appropriate point and start executing code until you get to the bottom
(apart from the else, which obviously should never happen).

To implement this in current Python, I'd probably do all the
comparisons as inequalities:

v = get("version")
if v<0:
raise UnknownVersionError("Version is below zero!")
if v<1:
commands_to_get_to_version_1
if v<2:
commands_to_get_to_version_2

# Version 3 is current.
set("version", 3)
if v>3:
raise UnknownVersionError("Version is moving backward!")

Which means this isn't really a terribly compelling use-case; but I
think it's a better one than overlapping ranges. Fall-through in
C-like languages completely ignores the case labels on subsequent
sections, and executes them because of their position in the file; I'm
not sure how it's looking with the current proposals, but it seems the
case statements would have to be written to catch the values from
above.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Terry Reedy

On 4/3/2014 12:02 PM, Lucas Malor wrote:


A more suitable place to propose this would be the python-ideas mailing list.


You're right. I posted here because this list was linked by PEP 1. But now that 
I read more there's also python-ideas listed. Let me know if I have to continue 
there instead.


Given that the idea has been posted to python-ideas and rejected, more 
that once I believe, I think this was the right place to post this to 
have variations discussed in a friendly manner.


--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Ethan Furman

On 04/03/2014 09:02 AM, Lucas Malor wrote:


In reply to Ian Kelly:


Instead of disabling fallthrough by default, why not disable it all together?


I was tempted but there are cases in which it's useful. An example

switch day casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
 gotowork = True
 continue
casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
 daytype = "ferial"
casein ("Saturday", "Sunday")
 daytype = "festive"



Absolutely not.  Currently, the 'continue' key word means "stop processing and go back to the beginning".  You would 
have it mean "keep going forward".  Thus 'continue' would mean both "go backwards" and "go forwards" and would lead to 
unnecessary confusion.


--
~Ethan~
--
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Ian Kelly
On Thu, Apr 3, 2014 at 10:02 AM, Lucas Malor <3kywjyd...@snkmail.com> wrote:
>> __contains__ is not part of the interface for iterables
>
> For what I know there's not an Iterable interface. For example List simply 
> extends Object. I hope that an ABC Iterable class will be introduced in a 
> future.

It already exists:

>>> import collections.abc
>>> isinstance([1,2,3], collections.abc.Iterable)
True

>> Instead of disabling fallthrough by default, why not disable it all together?
>
> I was tempted but there are cases in which it's useful. An example
>
> switch day casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
> gotowork = True
> continue
> casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
> daytype = "ferial"
> casein ("Saturday", "Sunday")
> daytype = "festive"

I don't see how it's useful there.  The first two cases are the same,
so just combine the code into one suite.  For overlapping cases where
the intersection needs to be handled by both suites, you can match
against the union and use conditionals to determine in more detail
which code to run.  For example, if you would write:

switch day case in ("Mon", "Wed", "Fri"):
lunch_time = datetime.time(12)
meeting_time = datetime.time(14)
continue
case in ("Tue", "Thu"):
lunch_time = datetime.time(11, 30)
meeting_time = datetime.time(12, 30)
continue
case in ("Mon", "Tue", "Wed", "Thu", "Fri"):
go_to_work = True
day_type = "ferial"
case in ("Sat", "Sun"):
go_to_work = False
day_type = "festive"

Use this instead:

switch day case in ("Mon", "Tue", "Wed", "Thu", "Fri"):
go_to_work = True
day_type = "ferial"
if day in ("Tue", "Thu"):
lunch_time = datetime.time(11, 30)
meeting_time = datetime.time(12, 30)
else:
lunch_time = datetime.time(12)
meeting_time = datetime.time(14)
case in ("Sat", "Sun"):
go_to_work = False
day_type = "festive"

You get an extra level of indentation this way, but it reads less like
spaghetti code.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-03 Thread Lucas Malor
Thank you for reading and commenting my proposal. Here are my replies:

In reply to Chris Angelico:

> I don't like the "iterable vs non-iterable" distinction. Compare: [...]
> case "Test": # And there's your problem.

Yes, I had already thought after I posted that testing against string it's a 
problem. But I think that the more practical and unambiguous solution is to 
introduce also "casein" as a new keyword. So if you want to test a string:

switch mystring case "-h":
print_usage()
case "--version"
print_version()

If you want to test against membership:

switch mychar casein "aeiou":
mychar.vocal = True

I prefer "casein" instead of "case in" for the same reason Python uses "elif" 
instead of "else if".



In reply to Ian Kelly:

> A more suitable place to propose this would be the python-ideas mailing list.

You're right. I posted here because this list was linked by PEP 1. But now that 
I read more there's also python-ideas listed. Let me know if I have to continue 
there instead.

> Why just just an identifier after the switch keyword instead of an expression?

Because I wronged, it can be an expression_list as well.

> An expression_list is one or more independent expressions separated by commas 
> that 
> don't create a tuple.

Well, py docs state "An expression list containing at least one comma yields a 
tuple".

> __contains__ is not part of the interface for iterables

For what I know there's not an Iterable interface. For example List simply 
extends Object. I hope that an ABC Iterable class will be introduced in a 
future. 
Anyway, I think that "switch x casein y" should simply raise a TypeError if y 
doesn't implement __contains__, like "x in y" do.

> If we overload the continue keyword in this way, then a continue can't be 
> used within the switch
> to control a loop that the switch is nested within.

Well, this is the same problem for, say, a for loop nested inside another for 
loop, and you can solve it with the same methods.

> Instead of disabling fallthrough by default, why not disable it all together?

I was tempted but there are cases in which it's useful. An example

switch day casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
gotowork = True
continue
casein ("Monday", "Thursday", "Wednesday", "Tuesday", "Friday"):
daytype = "ferial"
casein ("Saturday", "Sunday")
daytype = "festive"
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-02 Thread Ian Kelly
On Wed, Apr 2, 2014 at 7:06 PM, Steven D'Aprano  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.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-02 Thread Steven D'Aprano
On Thu, 03 Apr 2014 08:50:47 +1100, Chris Angelico wrote:

> On Thu, Apr 3, 2014 at 1:53 AM, Lucas Malor <3kywjyd...@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(1):
...

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
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-02 Thread Chris Angelico
On Thu, Apr 3, 2014 at 1:53 AM, Lucas Malor <3kywjyd...@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
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Yet Another Switch-Case Syntax Proposal

2014-04-02 Thread Ian Kelly
On Wed, Apr 2, 2014 at 8:53 AM, Lucas Malor <3kywjyd...@snkmail.com> wrote:
> Hi all. I would proposeto you all a switch-case syntax for Python. I already 
> read PEP 3103 and I'm not completely satisfied by any of the proposed 
> solutions. This is my proposal:

A more suitable place to propose this would be the python-ideas mailing list.

> switch_stmt ::=  "switch" identifier "case" expression_list ":" suite
> ("case" expression_list ":" suite)*
> ["else" ":" suite]

Why just just an identifier after the switch keyword instead of an
expression?  There are many cases where a user might wish to do
something along the lines of "switch values[0] case 42:"

> Expression list should yield an iterable. The case suite will be executed if 
> the variable of the identifier is a member of the iterable.

An expression_list is one or more independent expressions separated by
commas that don't create a tuple.  If you just want an iterable, then
it should just be one expression.  But I'm not sure I like that.
Additionally, what if the value that you want to match is itself a
tuple?  If I write "switch 1, 2, 3 case 1, 2, 3:" will it match
against the entire tuple or will it try to match against the
individual ints and fail?  I prefer the "case in" syntax of
Alternative B of PEP 3103 here; it reads naturally and makes explicit
in the syntax whether you're matching against an individual object or
a grouping of objects.

> 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.

__contains__ is not part of the interface for iterables; it is defined
for containers only.  So if the matching expression evaluates to a
container that could be the code equivalent, but for arbitrary
iterables the equivalent code would have to be:

for item in iterable:
if value == item:
# suite
break
else:
# move on to the next case

Which is unlikely to be any more efficient than a simple elif chain.

> Fallthrough is disabled by default. The continue keyword cause to skip all 
> the remaining current case suite. The next case will be checked. You can't 
> use the continue keyword in the else clause.

If we overload the continue keyword in this way, then a continue can't
be used within the switch to control a loop that the switch is nested
within.  Instead of disabling fallthrough by default, why not disable
it all together?  The container/iterable matching means that we can
already match multiple values to the same suite, so the only use
remaining for fallthrough would be the kind that creates code smell.

> Some random remarks:
> 1. switch is on the same line of the first case. This will avoid any 
> unpythonic syntaxes like:

I like this better than any of the alternatives in the PEP.

> 4. I decided to not use already existing keyword like "if" or "in", since it 
> will be misleading and problematic for syntax highlighters.

Syntax highlighters could easily distinguish between something like
"case in" and existing uses of "in".  The former starts with the
keyword "case", and the others do not.
-- 
https://mail.python.org/mailman/listinfo/python-list


Yet Another Switch-Case Syntax Proposal

2014-04-02 Thread Lucas Malor
Hi all. I would proposeto you all a switch-case syntax for Python. I already 
read PEP 3103 and I'm not completely satisfied by any of the proposed 
solutions. This is my proposal:

switch_stmt ::=  "switch" identifier "case" expression_list ":" suite
("case" expression_list ":" suite)*
["else" ":" suite]

or, more simply:



switch x case var1:

case var2:
...
case var3:
...
else:
...



Expression list should yield an iterable. The case suite will be executed if 
the variable of the identifier is a member of the iterable. 

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.

Fallthrough is disabled by default. The continue keyword cause to skip all the 
remaining current case suite. The next case will be checked. You can't use the 
continue keyword in the else clause.

Some random remarks:
1. switch is on the same line of the first case. This will avoid any unpythonic 
syntaxes like:
switch x
case var1:
...

or 

switch x:
case var1:
...

2. Fallthrough is disabled by default because IMHO it's what non-programmers 
expect and that's what programmer usually needs more. I don't think a switch 
with such a syntax needs a break statement. 

3. As an alternative, the continue statement could be written only at the end 
of a case suite; it will be less powerful and not consistent with the other 
compound statements, but it will improve readability.

4. I decided to not use already existing keyword like "if" or "in", since it 
will be misleading and problematic for syntax highlighters.


Tell me what you think about.
-- 
https://mail.python.org/mailman/listinfo/python-list