Open atyutin opened 13 years ago
Hi,
what ever happened to this? I just wanted to implement the same "pull"-driven behavior, tried to implement it using cached properties and stumbled upon the same issue of intermediate properties where updates are always triggered. I like this solution and at first glance seems to work for me. Is there any other more "official" way in traits 4.1 on how to implement that "lazy evaluation" pattern?
Hi,
I am pleased to know that someone has got seriously interested in this topic. I decided to stop promoting the idea after sccolbert mentioned that some mechanism implementing the discussed lazy evaluation pattern could be included in traits 4, please see comments on https://github.com/enthought/traits4/issues/1. Unfortunately, I don't know if anything like that was really implemented.
Hi,
indeed I read the comments, but could not find any hints on how this changed with Traits 4.0. Maybe I need to look for a changelog to traits 4...
I propose to add "lazy property" to the existing trait types. The purpose is to avoid unnecessary computations of property values and redundant trait notifications.
Consider first a standard property trait. Suppose that there are traits (call them “ancestors”) that the property depends on (which is the usual case for a non-trivial property), and there are also traits (“descendants”) that depend on the considered property. In short, we suppose that the property is an intermediate node in the traits notification network.
My concern is that each time such a property receives a notification that one of its ancestors has changed its value, it automatically recomputes its own value whether or not this value is going to be used.
I propose to add "lazy property" to the existing trait types. The purpose is to avoid unnecessary computations of property values and redundant trait notifications.
Consider first a standard property trait. Suppose that there are traits (call them “ancestors”) that the property depends on (which is the usual case for a non-trivial property), and there are also traits (“descendants”) that depend on the considered property. In short, we suppose that the property is an intermediate node in the traits notification network.
My concern is that each time such a property receives a notification that one of its ancestors has changed its value, it automatically recomputes its own value whether or not this value is going to be used.
In contrast, a “lazy property” should be such property that when it receives a notification, it does not update its value immediately, but postpones the updating until the value is actually requested (by a getattr method or alike). This "lazy evaluation" can be complemented with "lazy notification", which means that if the “lazy property” has already sent a notification, it does not send further notifications until its value is recomputed.
Let us now recall why the “usual” property with descendants automatically recomputes its value. This happens because the property must propagate the received notification, telling its descendants that its value is being updated, and the current implementation of Traits is such that the new value must be part of the notification. But is it really necessary to include the new value in the notification? Would it not suffice just to notify the descendants that the value is not valid anymore? More specifically, it appears to be no important reason to include both the old and the new values in the trait_change event. Posting only the old value would be sufficient, at least in most cases; the new value can be always readily computed by explicitly accessing the trait. However, to conform to the existing Traits framework, one can simply include the “Undefined” object in the trait notification instead of the real new value.
Where could "lazy properties" be useful? Clearly, the Traits properties offer an elegant syntax to implement a function as a composition of other functions (with an unlimited number of "intermediate" decomposition layers). This is useful in coding many mathematical models (in particular, in the context of Chaco visualization). But what can be said about the computational efficiency of this framework? A function coded as a "network" of properties reacts to any change of its inputs. This is acceptable if one wishes to trace the changes in function values caused by each change in each individual input. But suppose that we don't need the function value be recomputed after each change. We may wish to change a subset of the inputs, and evaluate the function after that. Here the standard properties become inefficient, resulting in unnecessary computations and notifications. Let me refer to my code below (or script lazy_property.py) for an illustration.
This ticket follows the discussion on the Enthought-Dev mailing list (see subject [Traits] Proposal: lazy property, initiated by Anton Tyutin on February 7, 2011). You can also find a link to script lazy_property.py there, which is a simple implementation of the "lazy evaluation" feature of “lazy properties”. This code is cited below for completeness.