Skip to content

Commit 200d016

Browse files
authored
Add a design topic page on lazy vs. eager implementations (#708)
Follow-up to gh-652, which added notes to the specifications for `__bool__` & co on this topic.
1 parent bbb4001 commit 200d016

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

spec/draft/design_topics/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Design topics & constraints
77

88
copies_views_and_mutation
99
data_dependent_output_shapes
10+
lazy_eager
1011
data_interchange
1112
device_support
1213
static_typing
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
.. _lazy-eager:
2+
3+
Lazy vs. eager execution
4+
========================
5+
6+
While the execution model for implementations is out of scope of this standard,
7+
there are a few aspects of lazy (or graph-based) execution as contrasted to
8+
eager execution that may have an impact on the prescribed semantics of
9+
individual APIs, and will therefore show up in the API specification.
10+
11+
One important difference is data-dependent or value-dependent behavior, as
12+
described in :ref:`data-dependent-output-shapes`. Because such behavior is hard
13+
to implement, implementers may choose to omit such APIs from their library.
14+
15+
Another difference is when the Python language itself prescribes that a
16+
specific type *must* be returned. For those cases, it is not possible to return
17+
a lazy/delayed kind of object to avoid computing a value. This is the case for
18+
five dunder methods: `__bool__`, `__int__`, `__float__`, `__complex__` and
19+
`__index__`. Each implementation has only two choices when one of these methods
20+
is called:
21+
22+
1. Compute a value of the required type (a Python scalar of type `bool`, `int`,
23+
`float` or `complex`), or
24+
2. Raise an exception.
25+
26+
When an implementation is 100% lazy, for example when it serializes a
27+
computation graph, computing the value is not possible and hence such an
28+
implementation has no choice but to raise an exception. For a "mostly lazy"
29+
implementation, it may make sense to trigger execution instead - but it is not
30+
required to, both choices are valid.
31+
32+
A common code construct where this happens is conditional logic, e.g.::
33+
34+
vals = compute_something()
35+
if all(vals):
36+
# The if-statement will make Python call the __bool__ method
37+
# on the result of `all(vals)`.
38+
do_something_else()
39+
40+
Note that the API does not contain control flow constructs, as of now, that
41+
would allow avoiding the implicit `__bool__` call in the example above. The
42+
only control flow-like function is `where`, but there's no function like `cond`
43+
to replace an `if`-statement.

0 commit comments

Comments
 (0)