
On Sun, Oct 31, 2021 at 2:43 PM <2QdxY4RzWzUUiLuE@potatochowder.com> wrote:
On 2021-10-30 at 18:54:51 -0700, Brendan Barnwell <brenbarn@brenbarn.net> wrote:
On 2021-10-30 18:29, Chris Angelico wrote:
Right. That is a very real difference, which is why there is a very real difference between early-bound and late-bound defaults. But both are argument defaults.
I don't 100% agree with that.
This seems to be the crux of this whole sub-discussion. This whole thing scratches an itch I don't have, likely because of the way I learned to design interfaces on all levels. A week or so ago, I was firmly in Brendan Barnwell's camp. I really don't like how the phrase "default value" applies to PEP-671's late binding, and I'm sure that there will remain cases in which actual code inside the function will be required. But I'm beginning to see the logic behind the arguments (pun intended) for the PEP.
Current versions of the PEP do not use the term "default value" when referring to late binding (or at least, if I've made a mistake there, then please point it out so I can fix it). I'm using the term "default expression", or just "default" (to cover both values and expressions). And yes; there will always be cases where you can't define the default with a simple expression. For instance, a one-arg lookup might raise an exception where a two-arg one could return a default value. That's currently best written with a dedicated object: _sentinel = object() def fetch(thing, default=_sentinel): ... attempt to get stuff if thing in stuff: return stuff[thing] if default is _sentinel: raise ThingNotFoundError return default In theory, optional arguments without defaults could be written something like this: def fetch(thing, default=pass): ... as above if not exists default: raise ThingNotFoundError return default But otherwise, there has to be some sort of value for every parameter. (I say this as a theory, but actually, the reference implementation of PEP 671 has code very similar to this. There's a bytecode QUERY_FAST which yields True if a local has a value, False if not. It's more efficient than "try: default; True; except UnboundLocalError: False" but will have the same effect.)
The human description language/wording is different; , but what Python spells "default value," Common Lisp spells "initform." Python is currently much less flexible about when and in what context default values are evaluated; PEP-671 attempts to close that gap, but is hampered by certain technical and emotional baggage.
Lisp's execution model is quite different from Python's, but I'd be curious to hear more about this. Can you elaborate? ChrisA