[Python-ideas] Delayed Execution via Keyword

David Mertz mertz at gnosis.cx
Sun Feb 19 12:31:27 EST 2017

On Sun, Feb 19, 2017 at 8:24 AM, Michel Desmoulin <desmoulinmichel at gmail.com
> wrote:

> A great proposal, although now I would have to explain to my students
> the subtle difference between:
> res = (print(i * i) for i in range(x))
> res = delayed [print(i * i) for i in range(x)]

> They seems doing something similar, but they really don't.

Well, at the introductory level they are kinda similar. I know the
mechanism would have to be different.  But at a first brush it's the
difference between delaying the whole concrete collection and delaying one
item at a time.  That wouldn't be terrible for a first Compsci lesson.

> def stuff(arg=delayed []):
> Does this mean we create a NEW list every time in the body function ? Or
> just a new one the first time than the reference stays in arg ?

I think this cannot make a new list each time.  Of course, I'm one of those
people who have used the mutable default deliberately, albeit now it's
mostly superseded by functools.lru_cache().

But the idea of a "delayed object" is one that transforms into a concrete
(or at least *different* value) on first access.  In a sense, the
transformation from a delayed object to an iterator is still keeping it
lazy; and clearly `x = delayed my_gen()` is a possible pattern.

The pattern of `def stuff(arg=delayed expensive_computation(): ...` is
important to have.  But as in my longer example, `arg` might or might not
be accessed in the function body depending on condition execution paths.
Still, once `expensive_computation()` happens one time, that should be it,
we have a result.  Obviously `list()` is not an expensive operation, but
the syntax cannot make a boundary for "how costly."

> The "delayed" keyword sounds a lot like something used in async io, so I
> like "lazy" much more. Not only it is shorter, but it convey the meaning
> of what we are doing better.

I like `lazy` too.

> a = (await|yield) lazy stuff
> a = lazy (await|yield) stuff (should it even allowed ?)
> a = (lazy stuff(x) for x in stuff)
a = lazy f'{name}' + stuff(age) # is there a closure where we store "name"
> and 'age'?

I don't quite have a clear intuition about how lazy/delayed and
await/yield/async should interact.  I think it would be perfectly
consistent with other Python patterns if we decided some combinations
cannot be used together.  Likewise you can't write `x = await yield from
foo`, and that's fine, even though `yield from` is an expression.

> First, if there is an exception in the lazy expression, Python must
> indicate in the stack trace where this expression has been defined and
> where it's evaluated.

Yes.  I mentioned that there needs to be *some* way, even if it's an ugly
construct, to find out that something is delayed without concretizing it.
I think the best idea is hinted at in my preliminary thought.

I.e. we can have a special member of a delayed object that does not
concretize the object on access.  So maybe `object._delayed_code` of
something similar.  Since it's the interpreter itself, we can say that
accessing that member of the object is not a concretization, unlike
accessing any other member.  Every object that is *not* a delayed/lazy one
should probably have None for that value.  But delayed ones should have, I
guess, the closure that would get executed on access (then once accessed,
the object becomes whatever the result of the expression is, with
`._delayed_code` then set to None on that transformed object).

> a = lazy stuff
> if a is not lazy:
>     print(a)

So my spelling would be:

a = lazy stuff

if a._delayed_code is not None:


> One last thing: my vote is not dropping the ":" in front of they keyword.

I think the colon has parser problems, as I showed in some examples.  Plus
I don't like how it looks.  But I'd much rather have `a = lazy: stuff` than
not have the construct at all, nonetheless.

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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20170219/b447da2d/attachment.html>

More information about the Python-ideas mailing list