On Mon, Dec 6, 2021 at 1:45 AM Steven D'Aprano <st...@pearwood.info> wrote:
>
> On Sat, Dec 04, 2021 at 06:11:08PM +0000, Barry Scott wrote:
>
> > There are many possible implementation of the late bound idea that
> > could create an object/default expression. But is it reasonable to
> > bother with that added complexity/maintenance burden for a first
> > implementation.
>
> Chris wants to throw the late-bound defaults into the body of the
> function because that's what we are currently forced to do to emulate
> late-bound defaults. But we are designing the feature from scratch, and
> we shouldn't be bound by the limitations of the existing idiom.

Not quite true. I want to have them syntactically as part of the body
of the function, and semantically as part of the function call. 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. All I want to change is the
way that defaults can be provided.

Tell me, what's the first bytecode instruction in the function g here?

def f(x):
    print(x)
    return lambda: x

In current CPython, it's not "LOAD_GLOBAL print". It's "MAKE_CELL x".
Conceptually, that's part of the framework of setting up the function
- setting up its local variables, providing a place for nonlocals. But
it's a bytecode at the start of the function's code object. (I'm not
sure when that became a bytecode instruction. It wasn't one in Python
2.7.) 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.

> Encapsulation is good. Putting late-bound expressions in their own
> function so that they can be tested is a good thing, not a problem to be
> avoided. Most of us have, from time to time, already moved the
> late bound default into its own function just to make it easy to test in
> isolation:
>
>     def func(arg=None):
>         if arg is None:
>             arg = _implementation()
>         # and now handle arg
>
> With my strategy, we get that isolation for almost for free. There is no
> extra effort needed on the programmer's side, no new name or top-level
> function needed.

And if you want an _implementation function for external testing,
you're still welcome to do that.

def func(arg=>_implementation()):
    ...

No magic, just perfectly normal coding practices. If something's
important enough to test separately, refactor it into a private
function so you can call it. Why should this happen automatically for
late-bound argument defaults? From what I can tell, the only syntactic
constructs which form separate code objects are those which need them
for namespacing purposes: class blocks, nested functions, genexps,
comprehensions. Default argument values are not separate namespaces,
so they shouldn't need dedicated stack frames, dedicated code objects,
or anything like that.

> Will people take advantage of it? Of course people won't bother if the
> default is `[]` but beyond a certain level of complexity, people will
> want to test the default expressions in isolation, to be sure that it
> does the right thing.
>

Beyond a certain level of complexity, the fact that argument defaults
are in the signature will naturally pressure people to refactor them
into their own functions. I don't think we'll see people putting
multiline argument default expressions directly into the function
header.

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/RMOYQVDWSZKOBVKP7E6LUUTBEBXKH6NP/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to