utility class: lazy data type

I wrote this class to support lazy evaluation and caching of values. It seems like it would be useful for inclusion as a miscellaneous class in boost. It seems like this pattern occurs pretty often in practice, it's even the fundamental implementation method for singletons, and at least I often have tons of boost::optionals in my code, with get accessors on the classes that check if there's a value, if not call a fetch function, and then return the value. It's cleaner to just call get every single time and not worry about it. I don't consider myself a guru, so suggestions on how to make it better are, of course, appreciated. template<class T> class lazy { public: explicit lazy(function<T ()> fetch) : _fetch(fetch) { } T get() { if (!_cached) _cached = _fetch(); return _cached.get(); } private: optional<T> _cached; function<T ()> _fetch; }; Perhaps such a class is too trivial to be included, but here it is nonetheless.

template<class T> class lazy { public: explicit lazy(function<T ()> fetch) : _fetch(fetch) { }
T get() { if (!_cached) _cached = _fetch(); return _cached.get(); }
private: optional<T> _cached; function<T ()> _fetch; };
I miss a set function; e.g. from parser you get a string which is interpreted as a number and used, later changed/rewritten and saved (e.g. by use of spririt's Qi & Karma) as string again. Maybe another pattern for this use case is appropriate? Regards, Olaf

On Mon, Jan 19, 2009 at 8:19 AM, Olaf Peter <ope-devel@gmx.de> wrote:
template<class T> class lazy { public: explicit lazy(function<T ()> fetch) : _fetch(fetch) { }
T get() { if (!_cached) _cached = _fetch(); return _cached.get(); }
private: optional<T> _cached; function<T ()> _fetch; };
I miss a set function; e.g. from parser you get a string which is interpreted as a number and used, later changed/rewritten and saved (e.g. by use of spririt's Qi & Karma) as string again. Maybe another pattern for this use case is appropriate?
Hmm, yes I never considered the case of writing the value back out to the original location it was fetched from. I think it would be easy to modify the class to support this. But you would still want to allow the case where there is no update function. So probably add a second constructor: template<typename T> explicit lazy(function<T ()> fetch) //empty_1ary_function is undefined here, but purpose is clear from context. //simple function returns void, 1 arg of type T, and does nothing : _fetch(fetch), _update(empty_1ary_function<void, T>()) { } template<typename T> explicit lazy(function<T ()> fetch, function<void (T)> update) : _fetch(fetch), _update(update) { } then add member function update (is the boolean arg here useful?) void update(T val, bool update_source=true) { if (update_source) _update(val); _cached = val; } Additionally I think a few utility methods method would also be useful. T force() { _cached = _fetch(); return _cached.get(); } bool is_cached() const { return _cached.is_initialized(); } Also slight bug in the original get method. It should use !_cached.is_initialized() instead of !cached. In case of optional<bool> Haven't compiled this code to see if it works,b ut I think it should.
participants (2)
-
Olaf Peter
-
Zachary Turner