On Sep 20, 2015, at 00:31, Steven D'Aprano firstname.lastname@example.org wrote:
On Sun, Sep 20, 2015 at 09:10:32AM +0300, Serhiy Storchaka wrote:
On 19.09.15 07:21, Guido van Rossum wrote: I do, but at least the '?' is part of an operator, not part of the name (as it is in Ruby?).
What to do with the "in" operator?
I'm not convinced that we should generalise this beyond the three original examples of attribute access, item lookup and function call. I think that applying ? to arbitrary operators is a case of "YAGNI". Or perhaps, "You Shouldn't Need It".
I agree. Seeing how far you can generalize something and whether you can come up with a simple rule that makes all of your use cases follow naturally can be fun, but it isn't necessarily the best design.
Also, by not trying to generalize uptalk-combined operators (or uptalk as a postfix unary operator of its own, which I was earlier arguing for...), the question of how we deal with ?? or ?= (if we want them) can be "the same way every other language does", rather than seeing what follows from the general rule and then convincing ourselves that's what we wanted.
Also, I think trying to generalize to all operators is a false generalization, since the things we're generalizing from aren't actually operators (and not just syntactically--e.g., stylistically, they're never surrounded by spaces--which makes a pretty big difference in the readability impact of a character as heavy as "?") in the first place.
Personally, I think ?? is the second most obviously useful after ?. (there's a reason it's the one with the oldest and widest pedigree); we need ?() because Python, unlike C# and friends, unifies member and method access; ? doesn't seem as necessary but it's such an obvious parallel to ?() that I think people will expect it; ?= is potentially as confusing as it is helpful. So, my suggestion would be just the first four. And keeping them simple, and consistent with other languages, no trying to extend the protection to other operators/accesses, no extra short-circuiting, nothing. So:
spam ?? eggs === spam if spam is not None else eggs spam?.eggs === spam.eggs if spam is not None else None spam?(eggs) === spam(eggs) if spam is not None else None spam?[eggs] === spam[eggs] if spam is not None else None
That's easy to define, easy to learn and remember, and pretty consistent with other languages. The one big difference is that what you write as "spam?.eggs(cheese)" in C# has to be "spam?.eggs?(cheese)" in Python, but I don't think that's a big problem. After all, in Python, spam.eggs is a first-class object, and one that's commonly passed or stored, so the obvious way to look at "spam.eggs(cheese)" is as explicitly chaining two separate things together (a __getattr__ with a descriptor __get__, and a __call__), so why shouldn't uptalking both operations be explicit?