On Mon, Dec 6, 2021 at 4:13 AM Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, Dec 06, 2021 at 02:08:46AM +1100, Chris Angelico wrote:
I want to have them syntactically as part of the body of the function, and semantically as part of the function call.
Then you'll love the status quo, because that's exactly what we have now! *wink*
Aaaaaand that's what I get for typing emails at 2AM. LOL. Syntactically as part of the signature of the function, is what I meant to say. Thanks for the correction.
As a function begins executing, a ton of stuff happens, including allocating arguments to parameters, and providing default values for optional parameters that weren't passed.
And neither of those things are part of the function body. They are set up *before* the function's code object is called.
Correct. Including handling default values.
All I want to change is the way that defaults can be provided.
Right. And the community reaction on this mailing list is underwhelming. Apart from Abe, who is rather vigourly in favour of the PEP as it stands, I'm not really sure this PEP has much support as it stands now.
And one of the most frequent issues raised is that **all** you want to do is change the way that the late defaults can be provided.
You're the PEP author, but maybe you should consider listening to community feedback? Just sayin'.
Believe you me, I am listening. And quite frankly, the tone of this list is sounding like "shut up, go away, don't do anything, because there are other proposals that nobody can be bothered writing up, but if they existed, they'd be way better than what you're doing". Not exactly encouraging, since nobody is willing to do the work of writing up proposals, but is plenty willing to criticize.
Tell me, what's the first bytecode instruction in the function g here?
def f(x): print(x) return lambda: x
Why do you think that is an argument against my position? As you said:
CPython bytecode is an implementation detail, and the fact that there's bytecode to do this or that is not part of the language definition.
Bytecode can and does change.
I'm talking about the language definition: late bound defaults should be compiled into their own publicly accessible callable functions. I don't care what bytecode is emitted to do that. Whatever it is, it will change in the future, without changing the Python semantics one whit.
Yes. So why is it a problem for the default's evaluation to be part of the function's bytecode? I don't understand why this is such a big hassle.
def func(arg=>_implementation()): ...
No magic, just perfectly normal coding practices.
You've just made a good argument against your own PEP. We don't need new syntax for late-bound defaults, just use the perfectly normal coding practices that have worked fine for 30 years.
Hmm.... you mean that "arg=>_implementation()" works currently? You're complaining that complicated argument defaults can't be separately tested, and that we need magic to do the refactoring for us and make them testable. I say that, if it needs to be separately tested, refactor it, and if it's simple enough to not be worth refactoring, it doesn't get separately tested. That's an argument against your "break it into a separate magical subfunction" proposal, but not against the PEP itself.
Sure. And why should early-bound defaults be available in a publicly accessible dunder attribute, when they could be compiled directly into the function code object?
Because they're part of the FUNCTION, not the CODE. There's a big difference. Consider: for i in range(10): def func(i=i): ... There is only one code object. There are multiple function objects, each with their own early-bound defaults. By definition, since the defaults are evaluated as part of the function definition, the code to evaluate that MUST be part of the surrounding context, not the function being defined. And it's not introspectable at the moment, only the resulting value is. You are asking for far more than the language currently offers in any related context.
Hell, the entire code object, and most of the function object, could be compiled into one great big opaque ball of mud. Aside from standard attributes inherited from object, all the function really needs is a name and a binary blob of everything else.
But that's not the sort of language we have.
Indeed. We have all kinds of useful introspection tools. And late-bound defaults already have quite a few introspection features, most notably a source-code-reconstruction of the expression. That's more than you get for early-bound defaults. (In discussing this, I have noted a hole in the specification: it would be nice to have a way to see, on the code object, which args have late-bound defaults. Consider that a specification bug to be fixed.) You're setting the bar for PEP 671 a long way higher than literally everything else in the language... and yet you refuse to code your own reference implementation for the better version that you propose. Any plans to put some code behind your words? ChrisA