On 2019-06-24 05:39, Andrew Barnert wrote:
On Jun 23, 2019, at 19:57, MRAB <pyt...@mrabarnett.plus.com> wrote:
> >> On 2019-06-24 02:43, Andrew Barnert wrote:
>> On Jun 23, 2019, at 13:33, MRAB <pyt...@mrabarnett.plus.com> wrote:
>> >> > Finally, under "For consideration: alternative syntaxes", my offering would be:
>> > > expr if condition1 and not condition2 else pass
>> >> This seems a lot more tenable than the original proposal. The “unless” seems both unnecessary and overly restrictive. Being able to specify “no argument/container element” in an expression is what the OP is really looking for, and spelling that “pass” makes sense, and then putting it inside the existing conditional expression gives the exact behavior the original example wanted without anything else new, ambiguous, or potentially confusing. >> >> But I think it still needs to be fleshed out. I get the feeling you aren’t seriously proposing this change as something you want, but if the OP agrees that it gives him everything he wants, maybe he’ll be willing to think through all the details. And anyway, most of the same questions apply to the OP’s proposal, they’re just a bit harder to get at.
> Correct. Whilst I can see its point, I'm not calling for it, but merely 
suggesting alternative syntax that I think would be clearer.
>> The big question is: if “pass” (or EMPTY) is allowed in (some) expressions, 
what happens if you use it somewhere illegal? For example, given than “1 if spam else 
pass” is a legal construct, is “return 1 if spam else pass” a SyntaxError (because 
that legal construct is something other than an expression), or is that a 
syntactically valid expression in a valid statement that just raises some kind of 
runtime error if the expression evaluates to “pass”, because return needs a value to 
return?
>> >> If it’s a syntax error, I think you really need to work through the language grammar and show what needs to change. My worry is that it would require duplicating half the nodes in the grammar (unless you literally can’t embed conditional-pass-expressions in any other construct except directly in an argument list or starred list—I assume you’d want to be able to put a conditional-pass inside parens, or inside another conditional-pass, if nothing else…), but I could easily be wrong. >> >> If it’s a runtime error, the grammar seems a lot simpler—just make “pass” a special keyword identifier like None or False and I think you’re done (presumably remove the pass statement, too)—but the semantics are more complicated. Even forgetting about statements, what does it mean to yield an expression that evaluates to pass, or to lambda one? >> >> Also, even within argument lists, container displays, and expression lists used for tuple values, I think there are some unclear things: can keyword-argument values, dict display keys and/or values, and starred and double-starred items be pass-valued, and, if so, what does that mean for each? >> >> Meanwhile, although argument lists and container displays were the original desired use cases (and presumably also expression lists used as “tuple displays”), the OP actually wanted this to be used in “any statement expression”, and gave an assert statement as an example. I’m not quite sure what it’s supposed to do there (does it skip the assert? if so, how is that different from asserting True anyway?), and even less sure how to extend that idea to all statements that use an expression anywhere. Is this actually a necessary part of the feature? If so, there’s obviously even more work to be done defining the syntax and/or semantics. >> >> Finally, it would be nice to see each example compared to the best way to do the same thing (presumably with iterable unpacking) in current Python, to see how much It actually improves readability. The only equivalents given by the OP are a case where you can just use an if statement (which looks better than the proposed new syntax—presumably the whole point of this is for cases where you can’t easily do that, as with arguments and list elements) and an expression that isn’t actually equivalent (if it were, this feature wouldn’t be needed at all). >> > As the "pass" indicates omission, it could really only be valid where an expression (possibly followed by a comma) can be omitted, which is as the top-level expression.

So that means you can’t combine a conditional pass expression into anything 
larger. You can’t even put it in parentheses. That already makes it seem a lot 
less usable, and makes it smell suspect as a concept too.

Also, it feels very strange that “pass” can be used as the else-value of a 
conditional expression, but not in any other kind of expression.

Also, at the statement level, you can already always trivially rewrite things, 
probably more readably, as an if statement. It’s only inside expression lists 
and expressions, where you can’t do so, that the feature seems at all 
compelling.

Plus, I don’t think it really works.

> For:
> > return expr if condition else pass > > When condition is true: > > return expr > > When condition is false: > > return

You’re getting two syntactically different statement forms, depending on the 
runtime value of condition. Of course that’s not impossible to implement, but 
it seems weird.

But the real problem is that return is one of the only places in the language 
that actually works this way. Almost every other place you can have an 
expression in a statement, either the expression is mandatory (e.g., you can’t 
write x = with nothing on the right, so if that’s what x = 2 if cond else pass 
means when not cond, what? a SyntaxError at runtime?), or leaving it out 
doesn’t mean “use a sensible default value” but “do something different” (e.g., 
raise MyException(stuff) if cond else pass). Also, what about expression 
statements? Under your rule, there’s just no statement at all if not cond 
(possibly leading to an IndentError at runtime?).

Meanwhile, this doesn’t work for the OP’s only statement example: assert spam 
if eggs else pass should not be the same as assert (a SyntaxError), or assert 
None (which raises an AssertionError because None is falsely), but do nothing 
at all. Which makes me think that maybe he’d expect your return statement to 
not return, rather than to return None.

> What about "yield"? The same?

Well, yield isn’t a statement, it’s an expression, so that already falls under 
your “only the top-level expression in a statement” rule.

> So, I can see a use for it only in places such as a tuple, list or set 
display, or a positional argument in an argument list.

The OP says it’s useful in assert.

But I agree with you, all the potentially good uses seem to be when the 
expression is part of comma-separated list of expressions. Which I think means 
only container displays, expression lists (which usually work as “tuple 
displays”, but it’s a separate piece of syntax, and you have to be careful with 
the 0- and 1-element cases), and argument lists.

But someone still needs to work out exactly what that means, and (if it’s going 
to be enforced syntactically rather than at runtime) what it does to the 
grammar. Because, again, I worry that the only way to allow, e.g., a 
starred_list to include pass elements is to fork half the nodes in the grammar 
underneath it.

> Not sure about a dict display or a keyword argument; that might be going too 
far!

It seems to me that there’s no reason to ban starred items and keyword 
arguments if they fall naturally out of the change, but no reason to go out of 
the way to add them if they don’t. The semantics should be pretty obvious to 
any reader, but there’s also an existing simple way to write it (*pass clearly 
should do the same thing as *(), inserting zero positional arguments, right?).

But dict displays, that could be confusing. Do you have to pass-value the key, 
or the value, or either of the two, or both consistently? If the key, does that 
short-circuit the value expression? So I think you’re right, that’s possibly 
worth banning even if you have to go out of your way to do so.

I'm now wondering whether we need the "else pass" part at all.

Currently the ternary 'if' expects an 'else' after the condition, but in a display a unary 'if' (should we call it that?) would be followed by ',' or 'for' or the end of the display.

Incidentally, I don't think a unary 'if' should skip a statement if the condition is false; that's what an 'if' _statement_ is for!

I'm not convinced of its usefulness anyway except as a way of omitting an item from a series of items.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/BQE6TBNXR2URBL633ESJDMFCYFOSDI3H/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to