On Fri, Mar 7, 2014 at 7:29 AM, Jim J. Jewett <jimjjewett@gmail.com> wrote:
The PEP currently says:
Alternative Proposals =====================
Discussion on python-ideas brought up the following syntax suggestions::
value = expr except default if Exception [as e]
This one was rejected because of the out-of-order evaluation.
Note, however, that the (farthest left) expr is always evaluated first; the only out-of-order evaluation is "default if Exception".
"default if Exception" is precisely the same evaluation order (clause after the "if" skips ahead of the clause before the "if") as in the existing if-expression, and the existing if-filters in comprehensions.
Yes, but that's still out of order.
The same justifications for that order violation generally apply here too. You can argue that they weren't sufficient justification in the first place, but that is water under the bridge; *re*-using out-of-order-"if" shouldn't add any additional costs.
[Err... unless people take the "if" too literally, and treat the Exception clause as a boolean value, instead of as an argument to the "except" keyword.]
The other thing to note is that it's somewhat ambiguous. Until you find that there isn't an else clause, it could be the equally valid "expr except (default if cond else other_default)", with the actual "if Exception" part still to come. (Style guides should, of course, decry this as unreadable, but both the machine parser and any humans reading the code have to assume style guides mightn't be followed.)
The advantages of this form get much stronger with [as e] or multiple different except clauses, but some of them do apply to even the simplest form.
Multiple different except clauses would make for an even messier evaluation order: expr1 except expr3 if expr2 except expr5 if expr4 If you consider the exception type to be the condition, then this makes sense (that is, if you read it as "if isinstance(thrown_exception, Exception)"); but the most obvious reading of "if", both in its statement form and as part of "true if expr else false", is that it is followed by something that's evaluated as boolean; and all exception types and tuples will be true in that context.
Notably, the "say it like you would in English" that convinced Perl still applies: "if" *without* a "then" is normally an extra condition added after the main point:
Normally ham, but fish if it's a Friday.
That's not how Python words ternary if, though. "Ham, if it's not Friday; otherwise fish" is closer, or inverting that: "Fish on Fridays, but normally ham". English is pretty flexible with how you lay things out :)
value = expr except (Exception [as e]: default)
(and the similar but unmentioned)
value = expr except (Exception [as e] -> default)
The parenthesizing question and the choice of tokens are considered independent, so not all the cross-multiplications are listed.
The mapping analogy for ":" is good -- and is the reason to place parentheses there, as opposed to around the whole expression. Your preferred form -- without the internal parentheses -- looks very much like a suite-introduction, and not at all like the uses where an inline colon is acceptable.
I have some notes on that down the bottom: http://www.python.org/dev/peps/pep-0463/#colons-always-introduce-suites
value = expr except Exception [as e] continue with default
This one works for me, but only because I read "continue with" as a compound keyword. I assume the parser would too. :D But I do recognize that it is a poor choice for those who see the space as a more solid barrier.
That depends on all parsers (computer and human) being okay with the two-keyword unit. Would have to poll human parsers to see how they feel about it.
value = expr except(Exception) default # Catches only the named type(s)
This looks too much like the pre-"as" way of capturing an exception.
Not sure what the connection is, but I don't like the style anyway: putting an expression immediately after a close parenthesis seems odd (I can't think of anything else in Python that has that).
value = default if expr raise Exception
(Without new keyword "raises",) I would have to work really hard not to read that as:
__temp = default if expr: raise Exception value = __temp
Yeah; on the flip side, "raises" doesn't add a huge amount of clarity, and it's creating a new keyword that's not identical, but so all-but - oh Saphir, is it not quite too "all-but"?
value = expr or else default if Exception
To me, this just seems like a wordier and more awkward version of
expr except (default if Exception [as e])
including the implicit parentheses around "default if Exception".
And mainly, it abuses three keywords that can all already exist in an expression, and doesn't use either "try" or "except". Suppose you saw that, and wanted to know what it does. What would you search the docs for?
value = expr except Exception [as e] -> default
Without parens to group Exception and default, this looks too much like an annotation describing what the expr should return.
Can expressions have annotations?
All forms involving the 'as' capturing clause have been deferred from this proposal in the interests of simplicity, but are preserved in the table above as an accurate record of suggestions.
Nick is right that you should specify whether it is deferred or rejected, because the simplest implementation may lock you into too broad a scope if it is added later.
Put it this way: It's deferred until there's a non-closure means of creating a sub-scope. If that never happens, then this is postponed indefinitely (like pay-day for the Dormouse's good workers); and that doesn't majorly bother me, because the "as" clause isn't very much used in the simple try/except that want to be made into expressions. Philosophically it's a nice thing to support, so it's not Rejected; but it's dependent on a feature that CPython doesn't have, and may never have. In theory, someone could implement subscopes in a different Python, and then reopen this part of the proposal as "CPython won't support it, but MyPy will, can we make this official please?"; I don't know that anyone would bother, but it'd be plausible with the syntax as given.
The four forms most supported by this proposal are, in order::
value = (expr except Exception: default) value = (expr except Exception -> default)
If there are not parentheses after "except", it will be very tempting (and arguably correct) to (at least mentally) insert them around the first two clauses -- which are evaluated first. But that leaks into
value = (expr except Exception): default
which strongly resembles the suite-starter ":", but has very little in common with the mapping ":" or the signature ":".
value = (expr except Exception) -> default
which looks like an annotation, rather than a part of the value-determination.
value = true_expr if cond else false_expr You can put parens around true_expr or cond, no problem, but you can't put them around both:
value = (true_expr if cond) else false_expr SyntaxError: invalid syntax
Why would you want to put them around the first two expressions here? It's exactly the same: you have a ternary operator, so you can't parenthesize two of its terms and one of its keywords. That breaks up the parse unit, visually and logically. So that simply wouldn't work. :) ChrisA