Agreed on the point about PEP 661, if this is accepted I don't think it
will have much to offer.

For what it's worth I'm a very strong +1 on PEP 671 as it stands. Thanks
for showing me something I didn't even know I wanted Chris :)

I'll confess though I'm not a fan of any of the alternate syntaxes. I think
=> works really well, particularly if lambdas in the form: `(*args) =>
expr` are added at some point in the future, because it establishes some
common semantics between both uses of the => operator (namely, deferred
code execution. In both cases the expression on the right of the => isn't
expected to execute when the block itself is executed, but rather at some
future point when something is called).

I'm not a big fan of =: because we already have := and I can imagine it
being quite easy for people to not remember which way around each one is
(and it's just generally more effortful to visually parse), since neither
of them has a particularly strong intuitive meaning. By contrast => looks
visually like an arrow, while <= and >= have the advantage that their
ordering corresponds to how you would say it out loud or in your head (less
than or equal to/greater than or equal to), so I don't think those symbols
have the same issue.

I also don't love ?= because ? is one of the last few reasonable symbols we
have available for new syntax (*cough* backtick *cough*, not even once).
Whether it ends up being used for something like PEP 505: None-aware
operators (if that is ever resurrected, I can only dream) or some other
future feature we have yet to imagine, I'd prefer the ? symbol remain
available without any baggage. I don't think the rationale for this PEP (as
much as I agree with it) is quite strong enough to use it up.

Anyways, I'm really hoping this gets accepted. Awesome proposal!


On Sun, Oct 24, 2021 at 11:36 AM Paul Moore <p.f.mo...@gmail.com> wrote:

> This should probably reference PEP 661 (Sentinel Values) which is
> being discussed on Discourse:
> https://discuss.python.org/t/pep-661-sentinel-values/9126
>
> It's a different proposal, but one of the major motivating use cases
> (if not the only one) for sentinels is handling function default
> values that can't be expressed at definition times. So how the two
> proposals interact should be discussed *somewhere*, IMO.
>
> Personally I'd choose to support this proposal, and take the view that
> it weakens the need for PEP 661 to the point where I'd prefer not to
> bother with that proposal.
>
> Paul
>
> On Sun, 24 Oct 2021 at 01:15, Chris Angelico <ros...@gmail.com> wrote:
> >
> > Incorporates comments from the thread we just had.
> >
> > Is anyone interested in coauthoring this with me? Anyone who has
> > strong interest in seeing this happen - whether you've been around the
> > Python lists for years, or you're new and interested in getting
> > involved for the first time, or anywhere in between!
> >
> > https://www.python.org/dev/peps/pep-0671/
> >
> > PEP: 671
> > Title: Syntax for late-bound function argument defaults
> > Author: Chris Angelico <ros...@gmail.com>
> > Status: Draft
> > Type: Standards Track
> > Content-Type: text/x-rst
> > Created: 24-Oct-2021
> > Python-Version: 3.11
> > Post-History: 24-Oct-2021
> >
> >
> > Abstract
> > ========
> >
> > Function parameters can have default values which are calculated during
> > function definition and saved. This proposal introduces a new form of
> > argument default, defined by an expression to be evaluated at function
> > call time.
> >
> >
> > Motivation
> > ==========
> >
> > Optional function arguments, if omitted, often have some sort of logical
> > default value. When this value depends on other arguments, or needs to be
> > reevaluated each function call, there is currently no clean way to state
> > this in the function header.
> >
> > Currently-legal idioms for this include::
> >
> >     # Very common: Use None and replace it in the function
> >     def bisect_right(a, x, lo=0, hi=None, *, key=None):
> >         if hi is None:
> >             hi = len(a)
> >
> >     # Also well known: Use a unique custom sentinel object
> >     _USE_GLOBAL_DEFAULT = object()
> >     def connect(timeout=_USE_GLOBAL_DEFAULT):
> >         if timeout is _USE_GLOBAL_DEFAULT:
> >             timeout = default_timeout
> >
> >     # Unusual: Accept star-args and then validate
> >     def add_item(item, *optional_target):
> >         if not optional_target:
> >             target = []
> >         else:
> >             target = optional_target[0]
> >
> > In each form, ``help(function)`` fails to show the true default value.
> Each
> > one has additional problems, too; using ``None`` is only valid if None
> is not
> > itself a plausible function parameter, the custom sentinel requires a
> global
> > constant; and use of star-args implies that more than one argument could
> be
> > given.
> >
> > Specification
> > =============
> >
> > Function default arguments can be defined using the new ``=>`` notation::
> >
> >     def bisect_right(a, x, lo=0, hi=>len(a), *, key=None):
> >     def connect(timeout=>default_timeout):
> >     def add_item(item, target=>[]):
> >
> > The expression is saved in its source code form for the purpose of
> inspection,
> > and bytecode to evaluate it is prepended to the function's body.
> >
> > Notably, the expression is evaluated in the function's run-time scope,
> NOT the
> > scope in which the function was defined (as are early-bound defaults).
> This
> > allows the expression to refer to other arguments.
> >
> > Self-referential expressions will result in UnboundLocalError::
> >
> >     def spam(eggs=>eggs): # Nope
> >
> > Multiple late-bound arguments are evaluated from left to right, and can
> refer
> > to previously-calculated values. Order is defined by the function,
> regardless
> > of the order in which keyword arguments may be passed.
> >
> >
> > Choice of spelling
> > ------------------
> >
> > Our chief syntax proposal is ``name=>expression`` -- our two syntax
> proposals
> > ... ahem. Amongst our potential syntaxes are::
> >
> >     def bisect(a, hi=>len(a)):
> >     def bisect(a, hi=:len(a)):
> >     def bisect(a, hi?=len(a)):
> >     def bisect(a, hi!=len(a)):
> >     def bisect(a, hi=\len(a)):
> >     def bisect(a, hi=`len(a)`):
> >     def bisect(a, hi=@len(a)):
> >
> > Since default arguments behave largely the same whether they're early or
> late
> > bound, the preferred syntax is very similar to the existing early-bind
> syntax.
> > The alternatives offer little advantage over the preferred one.
> >
> > How to Teach This
> > =================
> >
> > Early-bound default arguments should always be taught first, as they are
> the
> > simpler and more efficient way to evaluate arguments. Building on them,
> late
> > bound arguments are broadly equivalent to code at the top of the
> function::
> >
> >     def add_item(item, target=>[]):
> >
> >     # Equivalent pseudocode:
> >     def add_item(item, target=<OPTIONAL>):
> >         if target was omitted: target = []
> >
> >
> > Open Issues
> > ===========
> >
> > - yield/await? Will they cause problems? Might end up being a non-issue.
> >
> > - annotations? They go before the default, so is there any way an anno
> could
> >   want to end with ``=>``?
> >
> >
> > References
> > ==========
> >
> >
> > Copyright
> > =========
> >
> > This document is placed in the public domain or under the
> > CC0-1.0-Universal license, whichever is more permissive.
> > _______________________________________________
> > 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/KR2TMLPFR7NHDZCDOS6VTNWDKZQQJN3V/
> > Code of Conduct: http://python.org/psf/codeofconduct/
> _______________________________________________
> 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/I7ZLP2A4HTQZPNKQ7V7GED26S62L6Y5N/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
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/XTOGRTAMDUVXUVO3SE4EXHDBF5ZXSWYN/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to