On Fri, Dec 3, 2021 at 6:50 AM Oscar Benjamin <oscar.j.benjamin@gmail.com> wrote:
On Thu, 2 Dec 2021 at 17:28, Chris Angelico <rosuav@gmail.com> wrote:
On Fri, Dec 3, 2021 at 4:22 AM Nicholas Cole <nicholas.cole@gmail.com> wrote:
There is nothing that this proposal makes possible that is not already possible with more explicit code.
It's worth noting that "explicit" does not mean "verbose". For instance, this is completely explicit about what it does:
x += 1
It does not conceal what it's doing, yet it uses a very compact notation to say "augmented addition". The proposal in question uses an explicit symbol to indicate that the default should be late-bound.
In contrast, a less explicit and much worse proposal might be: "If the argument default defines a mutable object, construct a new one every time", so "def f(x=1):" would be early bound and "def f(x=[]):" would be late-bound. This is implicit behaviour, since it's not stated in the code which one is which.
A bit of an aside but I find it interesting that you pick += for the example here because there is very much an implicit behaviour with += that it mutates in-place or not depending on the mutability of the object in question (a property that is invisible in the code). For x += 1 you can guess that x is a number and remember that all the standard number types are immutable. Where you have e.g. mutable and immutable versions of a type though there is no way to know just by looking at the augmented assignment statement itself:
S1 = {1, 2, 3} S2 = frozenset(S1) S3, S4 = S1, S2 S3 |= {4} S4 |= {4} S1 {1, 2, 3, 4} S2 frozenset({1, 2, 3})
Is this implicitness a problem in practice? Usually it isn't but very occasionally it gives the kind of bug that can send someone banging their head against a wall for a long time.
It's only as implicit as every other operator. For instance, when you write "x + y", that might call type(x).__add__(y), and it might call type(y).__radd__(x). Is that implicit behaviour? It's very clearly defined (as is when each will happen). If there is no __iadd__ method, then += will fall back on + and =. I think you're confusing "implicit behaviour" with "polymorphic behaviour", which is a strong tenet of pretty much every modern object-oriented programming language. The precise behaviour depends on the types of the objects involved. That's not a problem; it's a spectacularly useful feature! And yes, sometimes complexity leads to banging heads on walls. If there's some weird bug in an __iadd__ method, it can be annoyingly difficult to track down. But ultimately, it's not that difficult to figure out exactly what a line of code does. (It's just impractical to do that simultaneously for every line of code.) ChrisA