On Sun, Oct 31, 2021 at 9:54 AM Brendan Barnwell <brenb...@brenbarn.net> wrote:
>
> On 2021-10-30 15:35, Chris Angelico wrote:
> > Bear in mind that the status quo is, quite honestly, a form of white
> > lie. In the example of bisect:
> >
> > def bisect(a, hi=None): ...
> > def bisect(a, hi=>len(a)): ...
> >
> > neither form of the signature will actually say that the default value
> > is the length of a. In fact, I have never said that the consumer
> > should eval it. There is fundamentally no way to determine the true
> > default value for hi without first figuring out what a is.
>
>         The way you use the term "default value" doesn't quite work for me.
> More and more I think that part of the issue here is that "hi=>len(a)"
> we aren't providing a default value at all.  What we're providing is
> default *code*.  To me a "value" is something that you can assign to a
> variable, and current (aka "early bound") argument defaults are that.
> But these new late-bound arguments aren't really default "values",
> they're code that is run under certain circumstances.  If we want to
> make them values, we need to define "evaluate len(a) later" as some kind
> of first-class value.

This is correct. In fact, the way it is in the syntax, the second one
is a "default expression". But the Signature object can't actually
have the default expression, so it would have to have either a default
value, or some sort of marker.

Argument defaults, up to Python 3.11, are always default values. If
PEP 671 is accepted, it will make sense to have default values AND
default expressions.

> > So which is better: to have the value None, or to have a marker saying
> > "this will be calculated later, and here's a human-readable
> > description: len(a)"?
>
>         Let me say that in a different way. . . :-)
>
>         Which is better, to have a marker saying "this will be calculated
> later", or to have a marker saying "this will be calculated later, and
> here's a human-readable description"?
>
>         My point is that None is already a marker.  It's true it's not a
> special-purpose marker meaning "this will be calculated later", but I
> think in practice it is a marker that says "be sure to read the
> documentation to understand what passing None will do here".

That's true. The trouble is that it isn't uniquely such a marker, and
in fact is very often the actual default value. When you call
dict.get(), the second argument has a default of None, and if you omit
it, you really truly do get None as a result.

Technically, for tools that look at func.__defaults__, I have Ellipsis
doing that kind of job. But (a) that's far less common than None, and
(b) there's a way to figure out whether it's a real default value or a
marker. Of course, there will still be functions that have
pseudo-defaults, so you can never be truly 100% sure, but at least you
get an indication for those functions that actually use default
expressions.

So what you have is a marker saying "this is either the value None, or
something that will be calculated later". Actually there are multiple
markers; None might mean that, but so might "<object object at
0x7f27e77f0570>", which is more likely to mean that it'll be
calculated later, but harder to recognize reliably. And in all cases,
it might not be a value that's calculated later, but it might be a
change in effect (maybe causing an exception to be raised rather than
a value being returned).

The markers currently are very ad-hoc and can't be depended on by
tools. There is fundamentally no way to do better than a marker, but
we can at least have more useful markers.

>         Increasingly it seems to me as if you are placing inordinate weight on
> the idea that the benefit of default arguments is providing a "human
> readable" description in the default help() and so on.  And, to be
> frank, I just don't care about that.  We can already provide
> human-readable descriptions in documentation and we should do that
> instead of trying to create gimped human-readable descriptions that only
> work in special cases.  Or, to put it even more bluntly, from my
> perspective, having help() show something maybe sort of useful just in
> the case where the person wrote very simple default-argument logic and
> didn't take the time to write a real docstring is simply not a
> worthwhile goal.

Interesting. Then why have default arguments at all? What's the point
of saying "if omitted, the default is zero" in a machine-readable way?
After all, you could just have it in the docstring. And there are
plenty of languages where that's the case.

I'm of the opinion that having more information machine-readable is
always better. Are you saying that it isn't? Or alternatively, that
it's only useful when it fits in a strict subset of constant values
(values that don't depend on anything else, and can be calculated at
function definition time)?

>         So really the status quo is "you can already have the human-readable
> description but you have to type it in the docstring yourself".  I don't
> see that as a big deal.  So yes, the status quo is better, because it is
> not really any worse, and it avoids the complications that are arising
> in this thread (i.e., what order are the arguments evaluated in, can
> they reference each other, what symbol do we use, how do we implement it
> without affecting existing introspection, etc.).

And it also allows an easy transformation for functions that currently
are experiencing issues from things being too constant. Consider:

default_timeout = 500
def connect(timeout=default_timeout):

If that default can be changed at run time, how do you fix the
function? By my proposal, you just mark the default as being
late-bound. With the status quo, now you need to bury the real default
in the body of the function, and make a public statement that the
default is None (or something else). That's not a true statement,
since None doesn't really make sense as a default, but that's what you
have to do to work around a technical limitation.

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/2W6M4FYUE7EYL4T4VAI5NI7SGTHM3OK4/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to