On Thu, Nov 4, 2021 at 4:30 AM Steven D'Aprano <st...@pearwood.info> wrote:
>
> On Thu, Nov 04, 2021 at 03:07:22AM +1100, Chris Angelico wrote:
>
> > def func(spam: list = []) -> str: ...
> >
> > Which part of that becomes late bound?
>
> The name "spam" of course. Without the parameter, nothing gets bound at
> all.

True, but the parameter will be bound at the same time (minor
implementation details aside) whether there's an early default, a late
default, or no default, and (orthogonally) whether a value was
provided by the caller. There's nothing early or late there.

> > The [], not the name "list", not the name "spam".
>
> The type annotation is irrelevant. Its an annotation. There's no sense
> that the earliness/lateness of the binding comes into it at all. The
> parameter spam is declared to be a list even if the function is never
> called and nothing gets bound to it at all.

Correct, the annotation is irrelevant - but it is between the name and
the default. That's why I'm using annotated examples here: to
emphasize that separation (which will happen in many codebases), and
to highlight the distinction between annotating the name and
annotating the expression.

> And the [] is merely the expression that is bound to the parameter.
>
> I say "merely", but of course the expression is important in the sense
> that if you want the default value to be an empty list, it won't do to
> use "Hello world" as the expression. Obviously.

Uhh, but that's exactly the bit that's evaluated at a different time.
So it's not "merely" the expression; it is the exact thing that we're
changing the behaviour of.

> But the parameter is, in a sense, more important than the default value,
> because the default value is only a default. If you pass an argument to
> the function, the default doesn't get used. So if you talk about the
> function (either in code, the function's body, or in actual prose), you
> will say something like:
>
>     if condition:
>         spam.append(eggs)
>
> "if this condition is true, append eggs to spam" rather than "...to the
> empty list" because it might not be the empty list. We talk about the
> parameter. The parameter is late bound. Not the empty list.

Of course! The parameter is FAR more important than the default, and
that's why it comes first. But it's not the parameter that changes.

> Late binding or early binding is a property of the identifier, not of
> the value that gets bound to it.

I disagree :) The identifier is bound in exactly the same way.

> I'm sure that we can make it unambiguous to the compiler, but we may not
> make it stand out sufficiently to the human reader. It should be front
> and centre, like the `*` in the `*args` and `**kwargs` syntax.

But *a and **kw are actually different parameter types. They change
the meaning of the parameter itself, and therefore annotate that.

> I personally feel that the @ symbol works as a prefix modifier on the
> parameter. But if you hate the @ symbol, I think that other prefix
> modifiers may also work:
>
>     $parameter=expression  # perhaps a little too like Sparameter
>     !parameter=expression  # "bang" parameter :-)
>     ^parameter=expression
>     >parameter=expression  # unary greater than :-)
>     ~parameter=expression

The at sign doesn't particularly bother me, the prefix does. So I'm
not really a fan of any of these alternatives.

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

Reply via email to