[Python-Dev] Why not make frames? [was: Alternative forms [was: PEP 463: Exception-catching expressions]]

2014-03-09 Thread Jim J. Jewett


TL;DR:

expr except (default if exc_expr)
expr (except default if exc_expr)
expr except (exc_expr: default)
expr (except exc_expr: default)

(1)  Group the exceptions with the default they imply.
(2)  inline-":" still needs () or [] or {}.
(3)  Consider the expression inside a longer line.
(3a)  Does the except expression need to be general, or would it work
  if it were limited to a subclause of variable assignments?
(3b)  What about comprehensions?




On Fri Mar 7 20:54:31 CET 2014, Chris Angelico wrote:
>On Sat, Mar 8, 2014 at 5:58 AM, Jim J. Jewett  wrote:
>> (Thu Mar 6 23:26:47 CET 2014) Chris Angelico responded:
>>> On Fri, Mar 7, 2014 at 7:29 AM, Jim J. Jewett  
>>> wrote:

 [ note that "x if y" already occurs in multiple contexts, and
   always evaluates y before x. ]

...

> I don't see except expressions as fundamentally more associated with
> if/else than with, say, an or chain, which works left to right.

I do, because of the skipping portion.

Short-circuiting operators, such as an "or" chain, never skip a clause
unless they are skipping *every* subsequent clause.

An "if" statement sometimes skips the (unlabeled in python) "then"
clause, but still processes the even-later "else" clause.

A "try" statement sometimes skips the remainder of the try suite but
still executes the later subordinate "except" and "finally" clauses.

Note that this only explains why I see "except" as more closely related
to "if" than to "or"; it isn't sufficient to justify going back to
execute the skipped clause later.  That said, going back to a previous
location is a lot easier to excuse after an error handler than in
"regular" code.



> Analysis of the Python standard library suggests that the single-if
> situation is *by far* the most common, to the extent that it'd hardly
> impact the stdlib at all to add multiple except clauses to the
> proposal. Do you have a strong use-case for the more full syntax?

I do not.

I dislike the arbitrary restriction, and I worry that lifting it later
(while maintaining backwards compatibility) will result in a syntax
wart, but I do not have a compelling use case for that later relaxation.



>> and I strongly prefer that they [the parentheses] be internal
>> (which you fear looks too much like calling a function named except).
>> In that case, it is:

>> expr1 except (expr3 if expr2)

> I'm still not really seeing how this is better.

For one thing, it makes it clear that the "if" keyword may be messing
with the order of evaluation.

I don't claim that syntax is perfect.  I do think it is less flawed
than the no-parentheses (or external parentheses) versions:

(expr1 except expr3 if expr2)
expr1 except expr3 if expr2

because the tigher parentheses correctly indicate that expr2 and expr3
should be considered as a (what-to-do-in-case-of-error) group, which
interacts (as a single unit) with the main expression.

I also think it is (very slighly) better than the
colon+internal-parentheses version:

expr1 except (expr2: expr3)

which in turn is far, far better than the colon versions with external
or missing parentheses:

(expr1 except expr2: expr3)
expr1 except expr2: expr3

because I cannot imagine reading an embedded version of either of those
without having to mentally re-parse at the colon.  An example assuming
a precedence level that may not be what the PEP proposes:

if myfunc(5, expr1 except expr2: expr3, "label"):
for i in range(3, 3*max(data) except TypeError: 9, 3):
   ...

if myfunc(5, (expr1 except expr2: expr3), "label"):
for i in range(3, (3*max(data) except TypeError: 9), 3):
   ...

if myfunc(5, expr1 except (expr2: expr3), "label"):
for i in range(3, 3*max(data) except (TypeError: 9), 3):
   ...

if myfunc(5, expr1 except (expr2: expr3), "label"):
for i in range(3, 3*max(data) (except TypeError: 9), 3):
   ...

if myfunc(5, expr1 except (expr3 if expr3), "label"):
for i in range(3, 3*max(data) (except 9 if TypeError), 3):
   ...

if myfunc(5, expr1 except (expr3 if expr3), "label"):
for i in range(3, 3*max(data) except (9 if TypeError), 3):

myarg = expr1 except (expr3 if expr2)
if myfunc(5, myarg, "label"):
limit = 3*max(data) except (9 if TypeError)
for i in range(3, limit, 3):

Yes, I would prefer to create a variable naming those expressions,
but these are all still simple enough that I would expect to have
to read them.  (I like constructions that get ugly just a bit faster
than they get hard to understand.)  If I have to parse any of them,
the ones at the bottom are less difficult than the ones at the top.



> With the colon version, it looks very much like dict display,

which is good, since that is one of the acceptable uses of inline-colon.

> only with different brackets around it; in some fonts, that'll be
> very easily confused.

I've had more trouble with comm

[Python-Dev] Scope issues [was: Alternative forms [was: PEP 463: Exception-catching expressions]]

2014-03-09 Thread Jim J. Jewett



On Fri Mar 7 20:54:31 CET 2014, Chris Angelico wrote:
> On Sat, Mar 8, 2014 at 5:58 AM, Jim J. Jewett  wrote:
>> (Thu Mar 6 23:26:47 CET 2014) Chris Angelico responded:

>>> ...[as-capturing is] deferred until there's a non-closure means of
>>> creating a sub-scope.

>> The problem is that once it is deployed as leaking into the parent
>> scope, backwards compatibility may force it to always leak into
>> the parent scope.  (You could document the leakage as a bug or as
>> implementation-defined, but ... those choices are also sub-optimal.)

> It'll never be deployed as leaking, for the same reason that the
> current 'except' statement doesn't leak:

I don't think that is the full extent of the problem.  From Nick's
description, this is a nasty enough corner case that there may
be glitches no one notices in time.

The PEP should therefore explicitly state that implementation details
may force the deferral to be permanent, and that this is considered an
acceptable trade-off.


-jJ

--

Sorry for the botched subject line on the last previous message.
If there are still threading problems with my replies, please
email me with details, so that I can try to resolve them.  -jJ

___
Python-Dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Why not make frames? [was: Alternative forms [was: PEP 463: Exception-catching expressions]]

2014-03-09 Thread Chris Angelico
On Mon, Mar 10, 2014 at 1:16 PM, Jim J. Jewett  wrote:
> On Fri Mar 7 20:54:31 CET 2014, Chris Angelico wrote:
>> I don't see except expressions as fundamentally more associated with
>> if/else than with, say, an or chain, which works left to right.
>
> I do, because of the skipping portion.
>
> Short-circuiting operators, such as an "or" chain, never skip a clause
> unless they are skipping *every* subsequent clause.
>
> An "if" statement sometimes skips the (unlabeled in python) "then"
> clause, but still processes the even-later "else" clause.
>
> A "try" statement sometimes skips the remainder of the try suite but
> still executes the later subordinate "except" and "finally" clauses.
>
> Note that this only explains why I see "except" as more closely related
> to "if" than to "or"; it isn't sufficient to justify going back to
> execute the skipped clause later.  That said, going back to a previous
> location is a lot easier to excuse after an error handler than in
> "regular" code.

This is a rather tenuous connection, I think. It also doesn't justify
a fundamentally out-of-order evaluation. Compare all of these, which
are - unless I've made a mistake somewhere - evaluated in the order
shown (that is, no lower-numbered will be evaluated after a
higher-numbered, but of course not everything will be evaluated):

if expr1:
stmt2
elif expr3:
stmt4
else:
stmt5

try:
stmt1
except expr2:
stmt3
except expr4:
stmt5
except:
stmt6
else:
stmt7
finally:
stmt8

value = expr1 or expr2 or expr3 or expr4

value = expr1 and expr2 and expr3 and expr4

# With the current recommendations in PEP 463
value = (expr1 except expr2: expr3)

value = expr2 if expr1 else expr3

The if expression is the *only* one that's out of order, and it's
justified by (a) "reading" correctly (ie being similar to English),
and (b) using two existing keywords, rather than creating a 'then'
keyword or using symbols.

Useful reading:

http://legacy.python.org/dev/peps/pep-0308/

Skip down to the "Detailed Results of Voting" section (sorry,
text/plain PEPs don't do hash links) and note that these four
proposals received the most support:

A.  x if C else y
B.  if C then x else y
C.  (if C: x else: y)
D.  C ? x : y

with more support for C and D than for A and B. B requires a new
keyword, D is all symbols, C is indistinguishable from the statement
without the parens, and A puts the expressions in the wrong order. All
of them are somewhat flawed but all of them have some merit, too. The
BDFL went for A (which proves that Python isn't a democracy), and
there's no explanation of the reasoning behind that, but in the
absence of a strong statement on the subject, I would say that the gap
between the above four options is sufficiently narrow that this can't
be used to justify out-of-order syntax in any other proposal.

>> Analysis of the Python standard library suggests that the single-if
>> situation is *by far* the most common, to the extent that it'd hardly
>> impact the stdlib at all to add multiple except clauses to the
>> proposal. Do you have a strong use-case for the more full syntax?
>
> I do not.
>
> I dislike the arbitrary restriction, and I worry that lifting it later
> (while maintaining backwards compatibility) will result in a syntax
> wart, but I do not have a compelling use case for that later relaxation.

That's one reason for the mandatory external parentheses. With some
real-world usage data from Python 3.5, if this were implemented
exactly per the PEP, a decision could be made in 3.6 to lift one of
two restrictions:

3.5: (expr1 except Exception2: expr3)
3.6 choice 1: expr1 except Exception2: expr3
3.6 choice 2: (expr1 except Exception2: expr3 except Exception4: expr5)

But these are incompatible. Lifting either restriction mandates the
retention of the other.

Note also that internal parens are less easily removed - it becomes
two distinct code branches. Removing the requirement to have external
parents simply means that old-style code is putting parens around an
expression, no different from:

value = (1 if x else 2)
value = (3 + 5)

and completely harmless. Allowing optional internal parens means
maintaining two syntaxes forever, and both human and computer parsers
would have to be compatible with both.

>>> and I strongly prefer that they [the parentheses] be internal
>>> (which you fear looks too much like calling a function named except).
>>> In that case, it is:
>
>>> expr1 except (expr3 if expr2)
>
>> I'm still not really seeing how this is better.
>
> For one thing, it makes it clear that the "if" keyword may be messing
> with the order of evaluation.

It still could be waiting for its else. I mean, it's bad code style,
but you theoretically could do this:

foo[x] except (IndexError if isinstance(foo,list) else KeyError): None

Really bad style and horribly unclear (and anyway, you could just
catch LookupError), but grammatically legal. Anything using the word
'if' in an 

Re: [Python-Dev] Scope issues [was: Alternative forms [was: PEP 463: Exception-catching expressions]]

2014-03-09 Thread Chris Angelico
On Mon, Mar 10, 2014 at 1:35 PM, Jim J. Jewett  wrote:
> The PEP should therefore explicitly state that implementation details
> may force the deferral to be permanent, and that this is considered an
> acceptable trade-off.

How about words to this effect?

"""Should there be, in future, a way to create a true subscope (which
could simplify comprehensions, except expressions, with blocks, and
possibly more), then this proposal could be revived; until then, its
loss is not a great one..."""

(I parked the time machine in the PSU's garage, thanks for lending me it!)

(The PSU does not exist, and therefore does not have a garage.)

ChrisA
___
Python-Dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com