Thanks Rob,

I recognize that I have so-far skirted the order-of-precedence concern. I
believe I have used parens in my example everywhere there might be a
question... But that's not a general description or rule.

I have a bunch of issues that I know I need to flesh out, many coming as
suggestions in this thread, which I appreciate. I just wanted to provide
something concrete to start the conversation.

FWIW, there is a bunch more at the link now than in my initial paste. But I
want to clarify more before I copy a new version into the email thread.

I haven't used Twisted in a while, but it is certainly an important
library, and I don't want to cause confusion. Any specific recommendation
on language to use?

On Wed, Jun 22, 2022, 8:45 PM Rob Cliffe via Python-ideas <
python-ideas@python.org> wrote:

> Thank you for your proposal David.  At last we have a counter-proposal to
> talk about.  A few points:
>
> (1) (As I pointed out in an earlier post) There is a flaw in using the
> syntax of an expression PRECEDED by a SOFT keyword:
>     x     =    later    -y
> With your proposal, x is assigned a deferred-evaluation-object which will
> be evaluated at some time later as "minus y", right?
> Erm, no.  This is already legal syntax for x being immediately assigned a
> value of "later minus y".
> If you put the soft keyword *after* the expression:
>     x  =  -y  later
> it may or may not read as well (subjective) but AFAICS would work.
> Alternatively you could propose a hard keyword.  Or a different syntax
> altogether.
>
> (2) Delayed evaluation may be useful for many purposes.  But for the
> specific purpose of providing late-bound function argument defaults, having
> to write the extra line ("n = n" in your example) removes much of the
> appeal.  Two lines of boilerplate (using a sentinel) replaced by one
> obscure one plus one keyword is not much if any of a win, whereas PEP 671
> would remove the boilerplate altogether apart from one sigil.  Under your
> proposal, I for one would probably stick with the sentinel idiom which is
> explicit.  I think "n=n" is confusing to an inexperienced Python user.
> You may not think this is important.  My opinion is that late-bound
> defaults are important. (We may have to agree to differ.)  Apart from
> anything else: Python fully supports early-bound defaults, why discriminate
> against late-bound ones?
>
> (3) You talk about "deferred objects" and in one place you actually say 
> "Evaluate
> the Deferred".  A "deferred" is an important object but a different concept
> in Twisted, I think calling it something else would be better to avoid
> confusion.
>
> Best wishes
> Rob Cliffe
>
>
> On 21/06/2022 21:53, David Mertz, Ph.D. wrote:
>
> Here is a very rough draft of an idea I've floated often, but not with
> much specification.  Take this as "ideas" with little firm commitment to
> details from me. PRs, or issues, or whatever, can go to
> https://github.com/DavidMertz/peps/blob/master/pep-9999.rst as well as
> mentioning them in this thread.
>
> PEP: 9999
> Title: Generalized deferred computation
> Author: David Mertz <dme...@gnosis.cx>
> Discussions-To:
> https://mail.python.org/archives/list/python-ideas@python.org/thread/
> Status: Draft
> Type: Standards Track
> Content-Type: text/x-rst
> Created: 21-Jun-2022
> Python-Version: 3.12
> Post-History:
>
> Abstract
> ========
>
> This PEP proposes introducing the soft keyword ``later`` to express the
> concept
> of deferred computation.  When an expression is preceded by the keyword,
> the
> expression is not evaluated but rather creates a "thunk" or "deferred
> object."
> Reference to the deferred object later in program flow causes the
> expression to
> be executed at that point, and for both the value and type of the object to
> become the result of the evaluated expression.
>
>
> Motivation
> ==========
>
> "Lazy" or "deferred" evaluation is useful paradigm for expressing
> relationships
> among potentially expensive operations prior their actual computation.
> Many
> functional programming languages, such as Haskell, build laziness into the
> heart of their language.  Within the Python ecosystem, the popular
> scientific
> library `dask-delayed <dask-delayed>`_ provides a framework for lazy
> evaluation
> that is very similar to that proposed in this PEP.
>
> .. _dask-delayed:
>    https://docs.dask.org/en/stable/delayed.html
>
>
> Examples of Use
> ===============
>
> While the use of deferred computation is principally useful when
> computations
> are likely to be expensive, the simple examples shown do not necessarily
> use
> such expecially spendy computations.  Most of these are directly inspired
> by
> examples used in the documentation of dask-delayed.
>
> In dask-delayed, ``Delayed`` objects are create by functions, and
> operations
> create a *directed acyclic graph* rather than perform actual
> computations.  For
> example::
>
>     >>> import dask
>     >>> @dask.delayed
>     ... def later(x):
>     ...     return x
>     ...
>     >>> output = []
>     >>> data = [23, 45, 62]
>     >>> for x in data:
>     ...     x = later(x)
>     ...     a = x * 3
>     ...     b = 2**x
>     ...     c = a + b
>     ...     output.append(c)
>     ...
>     >>> total = sum(output)
>     >>> total
>     Delayed('add-8f4018dbf2d3c1d8e6349c3e0509d1a0')
>     >>> total.compute()
>     4611721202807865734
>     >>> total.visualize()
>
> .. figure:: pep-9999-dag.png
>    :align: center
>    :width: 50%
>    :class: invert-in-dark-mode
>
>    Figure 1.  Dask DAG created from simple operations.
>
> Under this PEP, the soft keyword ``later`` would work in a similar manner
> to
> this dask.delayed code.  But rather than requiring calling ``.compute()``
> on a
> ``Delayed`` object to arrive at the result of a computation, every
> reference to
> a binding would perform the "compute" *unless* it was itself a deferred
> expression.  So the equivalent code under this PEP would be::
>
>     >>> output = []
>     >>> data = [23, 45, 62]
>     >>> for later x in data:
>     ...     a = later (x * 3)
>     ...     b = later (2**x)
>     ...     c = later (a + b)
>     ...     output.append(later c)
>     ...
>     >>> total = later sum(output)
>     >>> type(total)  # type() does not un-thunk
>     <class 'DeferredObject'>
>     >>> if value_needed:
>     ...     print(total)  # Actual computation occurs here
>     4611721202807865734
>
> In the example, we assume that the built-in function `type()` is special
> in not
> counting as a reference to the binding for purpose of realizing a
> computation.
> Alternately, some new special function like `isdeferred()` might be used to
> check for ``Deferred`` objects.
>
> In general, however, every regular reference to a bound object will force a
> computation and re-binding on a ``Deferred``.  This includes access to
> simple
> names, but also similarly to instance attributes, index positions in lists
> or
> tuples, or any other means by which an object may be referenced.
>
>
> Rejected Spellings
> ==================
>
> A number of alternate spellings for creating a ``Deferred`` object are
> possible.  This PEP-author has little preference among them.  The words
> ``defer`` or ``delay``, or their past participles ``deferred`` and
> ``delayed``
> are commonly used in discussions of lazy evaluation.  All of these would
> work
> equally well as the suggested soft keyword ``later``.  The keyword
> ``lazy`` is
> not completely implausible, but does not seem to read as well.
>
> No punctuation is immediately obvious for this purpose, although
> surrounding
> expressions with backticks is somewhat suggestive of quoting in Lisp, and
> perhaps slightly reminiscent of the ancient use of backtick for shell
> commands
> in Python 1.x.  E.g.::
>
>     might_use = `math.gcd(a, math.factorial(b))`
>
>
> Relationship to PEP-0671
> ========================
>
> The concept of "late-bound function argument defaults" is introduced in
> :pep:`671`.  Under that proposal, a special syntactic marker would be
> permitted
> in function signatures with default arguments to allow the expressions
> indicated as defaults to be evaluated at call time rather than at
> runtime.  In
> current Python, we might write a toy function such as::
>
>     def func(items=[], n=None):
>         if n is None:
>             n = len(items)
>         items.append("Hello")
>         print(n)
>
>     func([1, 2, 3])  # prints: 3
>
> Using the :pep:`671` approach this could be simplified somewhat as::
>
>     def func(items=[], n=>len(items)):
>         # late-bound defaults act as if bound here
>         items.append("Hello")
>         print(n)
>
>     func([1, 2, 3])  # prints: 3
>
> Under the current PEP, evaluation of a ``Deferred`` object only occurs upon
> reference.  That is, for the current toy function, the evaluation would not
> occur until the ``print(n)`` line.::
>
>     def func(items=[], n=later len(items)):
>         items.append("Hello")
>         print(n)
>
>     func([1, 2, 3])  # prints: 4
>
> To completely replicate the behavior of PEP-0671, an extra line at the
> start of
> the function body would be required::
>
>     def func(items=[], n=later len(items)):
>         n = n  # Evaluate the Deferred and re-bind the name n
>         items.append("Hello")
>         print(n)
>
>     func([1, 2, 3])  # prints: 3
>
>
> References
> ==========
>
> https://github.com/DavidMertz/peps/blob/master/pep-9999.rst
>
> Copyright
> =========
>
> This document is placed in the public domain or under the
> CC0-1.0-Universal license, whichever is more permissive.
>
>
>
> --
> Keeping medicines from the bloodstreams of the sick; food
> from the bellies of the hungry; books from the hands of the
> uneducated; technology from the underdeveloped; and putting
> advocates of freedom in prisons.  Intellectual property is
> to the 21st century what the slave trade was to the 16th.
>
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to 
> python-ideas-leave@python.orghttps://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-ideas@python.org/message/DQTR3CYWMLSRRKR6MBLZNTGCG762QNDF/
> 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/STVZXLIHMO3RO66RK5Z5NT7PX3VQFC6Z/
> 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/EOMPMP6SSBY5EVTUB76MA6Z5Q6XSIKGF/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to