Not coalescing around None-aware
Not coalescing around None-aware
Posted Dec 23, 2022 10:51 UTC (Fri) by mb (subscriber, #50428)In reply to: Not coalescing around None-aware by rrolls
Parent article: Not coalescing around None-aware
Holy mother of god.
That's a perfect example of why we shouldn't have this operator.
Seriously. Why don't you simply resolve the None-defaults before doing the calculation?
Even with the ?? operator it would be much cleaner to pull it out of the calculation expression.
Posted Dec 23, 2022 11:56 UTC (Fri)
by rrolls (subscriber, #151126)
[Link] (7 responses)
It's not about putting ?? in absolutely everywhere, either - just making it available for the places where it's useful, and then letting developers choose appropriate places to use it. ?? is no different to walrus, the if-else ternary, lambda functions, generator expressions, or whatever other inline "shorthand" constructions you can think of in that regard. You can easily write ugly code with those if you so choose, just as you can with ??.
For example, a toy "print" function might include "stream.write(msg + end ?? '\n')" - totally readable and the obvious expression to write. Of course, in this case we can just put end='\n' instead of end=None in the function signature, but in more complex real-world cases, where the default might need to be an object or vary depending on circumstances or whatever, that's not always appropriate.
Resolving defaults before doing calculations is something I do all the time in current Python, and it has its downsides - it's extra clutter in the function, and it can be hard to track which variables need to be resolved, which don't, and whether you've missed any, especially if there's a lot of variables involved. Clever type checking code assist helps massively with that, but it's a fairly recent development and it isn't going to work in absolutely all scenarios - for example when extracting data nested deep in the result of a json.load call. Sometimes, it's just cleaner to resolve the defaults inline.
Posted Dec 23, 2022 14:46 UTC (Fri)
by shironeko (subscriber, #159952)
[Link] (6 responses)
Posted Dec 23, 2022 17:44 UTC (Fri)
by rrolls (subscriber, #151126)
[Link] (5 responses)
There are plenty of examples in the PEP that demonstrate where ?? would be useful far better than I could.
Posted Dec 23, 2022 19:30 UTC (Fri)
by shironeko (subscriber, #159952)
[Link] (4 responses)
One common example in there is the practice of foo(optional=None) and then assigning a default value to optional right afterwards. clearly this calls for improving the default value syntax not the none operator because it'll still be ugly, just shorter. Maybe the default syntax should accept function call, then we get the added benefit of having the function signature more self documenting than just None and have to figure out what that means.
Posted Dec 24, 2022 6:35 UTC (Sat)
by NYKevin (subscriber, #129325)
[Link] (3 responses)
Improving the default syntax has been discussed endlessly, but it's probably never going to happen, because both of the obvious approaches are non-starters:
1. You can't introduce a new default syntax, because then you would have two default syntaxes, and that has generally been regarded as inferior to the status quo.
Posted Dec 24, 2022 6:42 UTC (Sat)
by shironeko (subscriber, #159952)
[Link] (2 responses)
Posted Dec 24, 2022 9:12 UTC (Sat)
by NYKevin (subscriber, #129325)
[Link]
My interpretation of your comment is that you want to allow us to write an arbitrary expression as the default value, and lazily evaluate that expression when the function is called. It is already legal Python syntax to put arbitrary expressions as the default value, so this example will demonstrate the backwards incompatibility of the second half (lazy evaluation) only:
If you make x=i evaluate lazily, then both versions would print 4. This is backwards incompatible, and it also leaves us with no obvious way to get the 2 behavior instead of the 4 behavior. (Of course, it can be done, but it requires additional boilerplate that nobody should have to write.)
On the other hand, if you are proposing some new syntax that doesn't look like a "regular" Python expression (or somehow "decorates" the default value to indicate that it should be evaluated lazily)... nobody wants to deal with two different default value syntaxes in the same language. That way lies madness.
Posted Dec 24, 2022 9:14 UTC (Sat)
by smurf (subscriber, #17840)
[Link]
Personally I'd just re-purpose the Walrus operator to do lazy evaluation when you (ab)use it in a "def" declaration, though that's probably a non-starter given the past contentious discussion on that topic.
Not coalescing around None-aware
Not coalescing around None-aware
Not coalescing around None-aware
Not coalescing around None-aware
Not coalescing around None-aware
2. You can't modify the semantics of the existing syntax, both because it would break backwards compatibility, and also because there is an actual use case for eager evaluation of default values (namely, forcing a closure to eagerly evaluate its closed-over variables) and so you would need to provide an alternative for that. The total amount of ugliness in the language would probably increase.
Not coalescing around None-aware
Not coalescing around None-aware
lazy = []
eager = []
for i in range(5):
lazy.append(lambda: i)
eager.append(lambda x=i: x)
print(lazy[2]()) # Prints 4
print(eager[2]()) # Prints 2
Not coalescing around None-aware