We seem to be arguing in circles and talking past each other here about nomenclature:
    f(arg=>dflt)
What does it matter if we call it "a default" or "just behaviour in the function" or "a Jabberwocky" or "<your name here>"?
The RELEVANT question should be "Is it useful"?
Best wishes
Rob Cliffe

On 09/12/2021 08:06, Brendan Barnwell wrote:
On 2021-12-08 23:12, Chris Angelico wrote:
On Thu, Dec 9, 2021 at 5:52 PM Brendan Barnwell <[email protected]> wrote:
        To try stating this in yet another way, currently if I have:

def f(a=<some code here>)

        <some code here> must be something that evaluates to a first-class
object, and the "argument default" IS that first-class object --- not
bytecode to generate it, not some behavior that evaluates the
expression, no, the default value is itself an object.  This would not
be the case for late-bound defaults under the PEP.  (Rather, as I
phrased it in another post, there would not "be" a late-bound default at
all; there would just be some behavior in the function to do some stuff
when that argument isn't passed.)
The VALUE is a first-class object - that's the result of evaluating
the expression. With early-bound defaults, that's the only thing that
gets saved - not the expression, just the resulting value. (Which can
be seen if you do something like "def f(x=0x100):", which will show
the default as 256.)
    Right, but that's what I'm saying.  To me it is not a default 
unless there is a value that gets saved.  Otherwise it is just 
behavior in the function.
Remember, a late-bound default is most similar to this code:

def f(a=<optional>):
     if a was omitted: a = <some code here>

And in that form, the code isn't available as a first-class object.
That's why I say that it is parallel to every other partial expression
in Python. Until you evaluate it, there is no first-class object
representing it. (A code object comes close, but it's more than just
an expression - it also depends on its context. A function requires
even more context.)
    Yes, but that's the point.  To me that code is quite a different 
matter from "a late-bound default" as I conceive it.  I get the 
impression that you really do see that code as "a late-bound default" 
but to me it is not at all.  It just behavior in the function.  It's 
true that the result is to assign a certain value to the variable, but 
that alone doesn't make it "a default" to me.
    I mean, maybe it would help if I say it this way.  To me here's 
kind of how a function works:
1. A function is distinct from other kinds of expression in that some 
things happen when you define it, and it also "saves" some things for 
later when you call it.
2. When you define it, it saves two things: some code to be run when 
it's called (i.e., the function body) and some values to be used if 
some arguments aren't provided.  (It probably saves some other stuff 
too like the docstring but these are the relevant ones for our 
purposes.)  It stores those values with a mapping to their 
corresponding arguments (that is if you do `def f(a=1, b=2)` it stores 
that 1 goes with a and 2 with b).
3. Those values that are saved to be used later are the argument 
defaults.  That's it.  The only thing that can "be an argument 
default" is a thing that is saved when the function is defined and is 
(maybe) retrieved later when it's called.  Everything that isn't a 
value is BEHAVIOR.  You can do other things to the function at def 
time (like replace it with another one using a decorator, effectively 
augmenting it somehow) but argument defaults are values, they're not 
behavior.
    From that perspective, there is all the difference in the world 
between what we currently have, which you apparently think of as sort 
of a "manual" late-bound default, and a real late-bound default, which 
would be a value that is stored at def time.  If the effect of writing 
the signature a certain way (e.g., `=>[]` instead of `=[]`) is not to 
store a value but to somehow manipulate the bytecode of the function 
body, I don't consider that an argument default; it's a behavioral 
modification more akin to a decorator that wraps the original function.
    Part of the reason I feel this way is because what we currently 
have is in no way restricted to specifying default values.  What if I 
have this:
def f(a=<optional>):
    if a was omitted and random.random() < 0.5: a = <some code here>

. . . or perhaps more realistically:

def f(a=<optional>, b=<optional>, c=<optional>):
    if a was omitted and 0 < b <= 5 and not c.some_boolean_attr:
        a = <some code here>

    Now what "is the default"?  Is there one?  There is no clear distinction between code in the function body that defines a "late-bound default" and code that just does something else.  In the former case the behavior is random.  In the latter case it may be that you can say in English what the "default" is, but I don't consider that an ARGUMENT default.  It may be default BEHAVIOR of the FUNCTION to decide in a certain way what to assign to that local variable, but that's not a default "of the argument", it's part of the function's defined behavior like anything else.  In order for me to consider it an argument default, it has to have some independent status as a "thing" that is individually associated with the argument, not simply rolled into the bytecode of the function as a whole.  For instance, this function has default behavior too:
def f(a=<optional>):
    if a was omitted:
        download_a_file_from_the_internet()
    else:
        dont_download_anything()

    But the behavior doesn't suddenly become "a default" just because the code happens to assign a value to a.
    In my conception you can't specify an argument default by means of 
modifications to the function body, because the function body is 
arbitrary code that can do anything.  The different between "an 
argument default" and "stuff that the function does as part of its 
behavior" is that the argument default is segmented out and has its 
own independent existence.
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/F54DWGWTMKBEE6U72MVMFUW2X2BWGHND/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to