|
| 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