Let me go back to the top and answer the original questions, then offer a few thoughts that have been germinating in my head through this discussion. Chris Angelico wrote:
I've just updated PEP 671 https://www.python.org/dev/peps/pep-0671/ with some additional information about the reference implementation, and some clarifications elsewhere. *PEP 671: Syntax for late-bound function argument defaults* Questions, for you all: 1) If this feature existed in Python 3.11 exactly as described, would you use it?
Yes, but reluctantly. I take advantage of the features the language I'm using offers, even if I dislike them. And I greatly dislike this and would rather not have it for reasons described below.
2) Independently: Is the syntactic distinction between "=" and "=>" a cognitive burden? (It's absolutely valid to say "yes" and "yes", and feel free to say which of those pulls is the stronger one.)
Yes. When a single punctuation character distinguishes between two closely related but significantly different behaviors, that is a large cognitive burden because it slows down code reading. I am used to scanning through unfamiliar code quickly, as I frequently go through the code of third-party modules, and if this becomes a thing, I would have to stop and slow down to check whether argument defaults are being bound early or late to comprehend the code I'm reading. I don't want that.
3) If "yes" to question 1, would you use it for any/all of (a) mutable defaults, (b) referencing things that might have changed, (c) referencing other arguments, (d) something else?
Whatever appropriate uses arise. Most likely that would be mutable defaults like `[]` and `{}`. Referencing other arguments might be useful as well. I don't see any use for (b) in my code.
4) If "no" to question 1, is there some other spelling or other small change that WOULD mean you would use it? (Some examples in the PEP.)
Well, my answer to Q1 was "yes but I'd rather not". Frankly, there is no similar spelling that sounds reasonable to me.
5) Do you know how to compile CPython from source, and would you be willing to try this out? Please? :)
Yes, but no. Because I hate it. ;)
I'd love to hear, also, from anyone's friends/family who know a bit of Python but haven't been involved in this discussion. If late-bound defaults "just make sense" to people, that would be highly informative.
Late-bound defaults absolutely "just make sense". Way more sense than early-bound to me. This is reflected in the review of languages that Steven D'Aprano did a few days ago, where 80% of languages with syntax for default argument values use late binding, and all that bind early restrict default values to constants. Thus, when non-constant values are allowed as default values, current Python is entirely unique (among that list) in doing early binding. Early binding of non-constants has too many "gotcha"s and no real benefits, and any decent language being developed today ought to use late binding. Unfortunately, we can't remake the past. Python is stuck with the wart of early binding. Note that on that list of languages Steven produced, **none** offer both early and late binding. Arguably, offering both and expecting users to grok which is which is *worse* than the current wart of a single behavior that works in one way and is not difficult to work around. And therefore I believe that Python should not in any case offer both behaviors simultaneously. My preferences to resolve this are, in order: 1. Introduce `from __future__ import late_default`. When present, argument defaults in that file are late bound instead of early bound. After a suitable deprecation period, make the future statement the default behavior. Then Python will comply with best practices demonstrated by Steven's language review. I have not done any analysis, but I believe based on intuition that any breakage in libraries and scripts stemming from this would be relatively easy to fix, and most existing code should just work (in particular, the common existing usage of a sentinel as a default with an `is None` or `is sentinel` check in the body would not break and could be migrated to the new behavior at leisure). If true, it would result in minimal fuss for maximum benefit. 2. If a future statement and behavior change is deemed too disruptive, then keep early binding, do not introduce late binding, and introduce a new use for the keyword `pass` to represent an absent argument. Under this idea, `pass` would be accepted as an expression in the following three contexts, and exactly nowhere else: a) as a complete argument to a call, b) as a complete "value" for an argument default, and c) in the expressions `x is pass` and `x is not pass`, but only when both `x` is a parameter to the immediately enclosing function and the default value of that parameter is `pass`. This way, `pass` acts as a sentinel that isn't a valid value in any other context, which would solve the issue of when `None` is a valid value. 3. If both of those are undesired, then keep the wart in the status quo, and don't add late binding in any form.
Any and all comments welcomed. I mean, this is python-ideas after all... bikeshedding is what we do best!
Let's build a garage instead. ;)