What is a good idiom for handling a lazy object?

S

Siemel Naran

What is a good idiom for handling a lazy object? I see 2 good
possibilities. Any more, any comments? Which way do people here use?


(1)

class Thing {
public:
Thing(double x, double y) : x(x), y(y), calculated(false) { }
double operator()() const {
if (!calculated) calculate();
return z;
}
private:
double x;
double y;
mutable bool calculated;
mutable double z;
void calculate() { z = x+y; }
};


(2)

class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};
 
S

Steven T. Hatton

Siemel said:
What is a good idiom for handling a lazy object? I see 2 good
possibilities. Any more, any comments? Which way do people here use?


(1)

class Thing {
public:
Thing(double x, double y) : x(x), y(y), calculated(false) { }
double operator()() const {
if (!calculated) calculate();
return z;
}
private:
double x;
double y;
mutable bool calculated;
mutable double z;
void calculate() { z = x+y; }
};


(2)

class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};

I just want to acknowledge having looked at this post. I this is a good
question, but my requier a bit more background. I did a google on lazy
object, and found this: http://c2.com/cgi/wiki?LazyObject

I know Stroustrup covers something similar to this in TC++PL(SE), I hope to
be able to revisit the topic soon. It would probably help me evaluate your
code if you explained just a bit more in your own words what your design
objectives are.
 
V

Victor Bazarov

Siemel Naran said:
What is a good idiom for handling a lazy object? I see 2 good
possibilities. Any more, any comments? Which way do people here use?


(1)

class Thing {
public:
Thing(double x, double y) : x(x), y(y), calculated(false) { }
double operator()() const {
if (!calculated) calculate();
return z;
}
private:
double x;
double y;
mutable bool calculated;
mutable double z;
void calculate() { z = x+y; }

void calculate() const { z = x+y; calculated = true; }
};


(2)

class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};

I am not sure why you need to make such a long way around it. Besides,
I was always told that if you need to use dynamic_cast, you should re-
approach your design, it may have too many interdependencies.

Victor
 
S

Siemel Naran

Steven T. Hatton said:
I just want to acknowledge having looked at this post. I this is a good
question, but my requier a bit more background. I did a google on lazy
object, and found this: http://c2.com/cgi/wiki?LazyObject

Right, that describes it well.
I know Stroustrup covers something similar to this in TC++PL(SE), I hope to
be able to revisit the topic soon. It would probably help me evaluate your
code if you explained just a bit more in your own words what your design
objectives are.

I have created a Select object. Option 1 is for the constructor to open the
SQL connection, run the query, etc. Option 2 is for the constructor to just
store the function argument parameters. Only when we start iterating with
Select::for_each or whatever, then open the connection, do the query, etc.
This way we only open the connection when we really need it. Also, we
mininimize the number of connections, because we don't want temporary Select
objects such as those returned from functions to open a connection.

As another example I have written,

class Income
{
public:
...

double total() const
{
if (!m_hastotal)
{
m_total=
d_salary
+d_interest+d_dividends
+d_shortterm+d_longterm
;
m_hastotal=true;
}
return m_total;
}


private:
double d_salary;
double d_interest;
double d_dividends;
double d_shortterm;
double d_longterm;
mutable bool m_hastotal;
mutable double m_total;


This way a second call to income.total() doesn't have to do any
calculations. Not that adding 5 doubles is a big deal anyway, but I was
just playing around here.
 
S

Siemel Naran

Victor Bazarov said:
void calculate() const { z = x+y; calculated = true; }

Thanks, good catch!
I am not sure why you need to make such a long way around it. Besides,
I was always told that if you need to use dynamic_cast, you should re-
approach your design, it may have too many interdependencies.

The second way seems good for complex objects as we construct a whole new
object like Eval whose constructor garauntees all parts of the objects (the
private member variables) are initialized properly. Using the 1st way means
we have a super-class with all the variables (to store the lazy parameters x
and y, as well as the result variables), and it seems fine for simple
classes like my Income example in the other post and the class above. For
more complex classes the 2nd way forces the use of a constructor, which is a
nice way to fully initialize an object.

And yes, the use of dynamic_cast is a little bothersome, but it's really
just an if statement. I think it's OK in this context because class Thing
knows about the existence of class Lazy and Eval, and these are probably all
in one cpp file.
 
S

Steven T. Hatton

Siemel said:
Thanks, good catch!

Yup. That had me a bit confused.

Just tracing this through out loud:

Answer doesn't look like a very useful class. I assume you are creating it
to share acommon type, and, in particular the same descructor.

You've exposed Lazy::x and Lazy::y to Eval.

I believe you meant to put a semicolon at the end of the above line. No?
This returns Eval::z no matter what. No magic involved, right?

This doesn't make sense to me. You seem to be returning a value in a
function whose return type is void.

I believe you /can/ access lazy.x and lazy.y because of the friendship
relationship;

This seems like a magical incantation to to check the type. Perhaps it's
common in C++, but I find it a bit more subtle than code perhaps should be.

I don't like assert. But then I think checked exceptions are a good thing.
Why did you use it here?
[snip]
And yes, the use of dynamic_cast is a little bothersome, but it's really
just an if statement.

As far as casts go, dynamic_cast seems the least harmful. The only problem I
have with the way it's used it the subtlety of the test. It looks like a
convoluted instanceof test. I hit this example of instanceof on a google:
http://www.artefaktur.com/acdk/docs/hb/lang/acdk_hb_lang_instanceof-de.html
I think it's OK in this context because class Thing
knows about the existence of class Lazy and Eval, and these are probably
all in one cpp file.

I'm inclined to believe there is a more concise and direct way of
accomplishing the same goal. But I really don't know what that would be.

This is just something to consider:
http://www.rube-goldberg.com/html/gallery.htm

Please don't take it too seriously, especially since I have not provided a
better solution.
 
T

tom_usenet

What is a good idiom for handling a lazy object? I see 2 good
possibilities. Any more, any comments? Which way do people here use?


(1)

class Thing {
public:
Thing(double x, double y) : x(x), y(y), calculated(false) { }
double operator()() const {
if (!calculated) calculate();
return z;
}
private:
double x;
double y;
mutable bool calculated;
mutable double z;
void calculate() { z = x+y; }
};


(2)

class Answer {
virtual ~Answer();
};

class Lazy : public Answer {
public:
Lazy(double x, double y) : x(x), y(y) { }
private:
friend class Eval;
double x;
double y;
};

class Eval : public Answer {
public:
Eval(const Lazy& lazy) : z(calculate(lazy))
double operator()() const { return z; }
private:
double z;
static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
};

class Thing {
public:
Thing(double x, double y) : answer(new Lazy(x, y)) { }
double operator()() const {
const Lazy * lazy = dynamic_cast<const Lazy *>(answer.get());
if (lazy) {
answer.reset(new Eval(*lazy));
}
const Eval * eval = static_cast<const Eval *>(answer.get());
assert(eval);
return (*eval)();
}
private:
mutable boost::shared_ptr<Answer> answer;
};

How about something like this:

template <class T /*, threading policy? */>
class LazyValue
{
public:
typedef boost::function<T()> creator_t;
LazyValue(creator_t creator)
:m_creator(creator){}

T& get()
{
if (m_creator)
{
m_value = m_creator();
//reset creator
m_creator = creator_t();
}
return m_value;
}

private:
T m_value;
boost::function<T()> m_creator;
};

class Thing {
public:
Thing(double x, double y) : x(x), y(y),
z(bind(&Thing::calculate, this)) { }
double operator()() const {
return z.get();
}
private:
double x;
double y;
mutable LazyValue<double> z;
double calculate() const { return x+y; }
};

This idea can be extended to produce policy controlled, lazy, memory
usage limiting caches (I've done so in Java - a C++ implementation
would be much better. The policies were thread safety, minimum cache
size, how long unused references are held onto, etc. We used it for
loading large configuration objects, XML files, schemas, etc.).

Tom
 
S

Siemel Naran

I am not sure why you need to make such a long way around it. Besides,
I was always told that if you need to use dynamic_cast, you should re-
approach your design, it may have too many interdependencies.

Thinking about your comment on dynamic_cast, I can get rid off it and also
the derivation from Answer (though we now store both objects in memory, not
that that's a bad thing).

class Thing {
public:
Thing(double x, double y) : lazy(new Lazy(x, y)) { }
double operator()() const {
if (!eval) eval.reset(new Eval(*lazy));
return (*eval)();
}
private:
boost::shared_ptr<Lazy> lazy;
mutable boost::shared_ptr<Eval> eval;
};
 
S

Siemel Naran

Steven T. Hatton said:
Siemel Naran wrote:

I believe you meant to put a semicolon at the end of the above line. No?

Actualy { }

This returns Eval::z no matter what. No magic involved, right?
Right.




This doesn't make sense to me. You seem to be returning a value in a
function whose return type is void.

Sorry, the return type should be double.
I believe you /can/ access lazy.x and lazy.y because of the friendship
relationship;



This seems like a magical incantation to to check the type. Perhaps it's
common in C++, but I find it a bit more subtle than code perhaps should
be.

Yes, the use of dynamic_cast (or typeid) doesn't seem nice. On the other
hand, the classes Lazy and Eval are so tightly coupled (with one a friend to
the other), and they're probably declared in the same cpp file, so it's not
so bad. But I was thinking about Victor's point, and came up with a
solution that does not use dynamic_cast. Let me know if you think if that
is clearer.
I don't like assert. But then I think checked exceptions are a good thing.
Why did you use it here?

To assert that if lazy is false then eval must be true. In the other words,
when the lazy object is destroyed the eval object ought to be created. It
checks the logic of the previous if clause. But my other solution does not
have assert.


Huh?
 
S

Siemel Naran

How about something like this:

template <class T /*, threading policy? */>
class LazyValue
{
public:
typedef boost::function<T()> creator_t;
LazyValue(creator_t creator)
:m_creator(creator){}

T& get()
{
if (m_creator)
{
m_value = m_creator();
//reset creator
m_creator = creator_t();
}
return m_value;
}

private:
T m_value;
boost::function<T()> m_creator;
};

Just a side question. Is boost::function<T()> the same as
boost::function<T>? Anyway, this seems similar to my method #2 with the
modification Victor suggested -- not using dynamic_cast, instead store two
objects representing the raw data (class Lazy in my example, m_creator in
yours) and evaluated data (class Eval in my example, m_value in yours).
class Thing {
public:
Thing(double x, double y) : x(x), y(y),
z(bind(&Thing::calculate, this)) { }
double operator()() const {
return z.get();
}
private:
double x;
double y;
mutable LazyValue<double> z;
double calculate() const { return x+y; }
};

Does this boost::function thing handle functions take one, two, or three
arguments?
This idea can be extended to produce policy controlled, lazy, memory
usage limiting caches (I've done so in Java - a C++ implementation
would be much better. The policies were thread safety, minimum cache
size, how long unused references are held onto, etc. We used it for
loading large configuration objects, XML files, schemas, etc.).

Interesting. I didn't think about thread safety. When would it be an
issue? Is it when you create a LazyValue object and pass it to 2 different
threads?

And can you elaborate on this idea of minimum cache size?
 
A

anon luker

Siemel Naran said:
What is a good idiom for handling a lazy object?

I think that accessor functions are necessary and sufficient.
I see 2 good possibilities.
Any more, any comments? Which way do people here use?

A cursory glance at your code leaves me thinking that you really mean
to ask if there are any C++ idioms for memoizing. This is a more
interesting question, IMHO, and I would be inclined to answer no.
Seldom does a quality C++ library use the same interface for costly
operations as for trivial ones; a more typical C++ idiom would be to
have a costly operation that may return quickly under trivial
conditions. Further, since the underlying semantics for caching block
I/O may be wildly different from those for caching numeric
computations, unifying the interfaces for the two may not be
constructive. Having said all of that, I'm told that the proxy
pattern is useful in developing caching systems.

-cheers,
prs
 
S

Siemel Naran

anon luker said:
A cursory glance at your code leaves me thinking that you really mean
to ask if there are any C++ idioms for memoizing. This is a more
interesting question, IMHO, and I would be inclined to answer no.

What is "memoize"? Could not find it in the Merriam-Webster dictionary.
Seldom does a quality C++ library use the same interface for costly
operations as for trivial ones; a more typical C++ idiom would be to
have a costly operation that may return quickly under trivial
conditions.

Can you give an example?
Further, since the underlying semantics for caching block
I/O may be wildly different from those for caching numeric
computations, unifying the interfaces for the two may not be
constructive. Having said all of that, I'm told that the proxy
pattern is useful in developing caching systems.

What do you mean by sentence #1?
 
A

anon luker

Siemel Naran said:
What is "memoize"? Could not find it in the Merriam-Webster dictionary.

Google "memoize" - Results 1 - 30 of about 13,000 for memoize. (0.38
seconds)
Can you give an example?

I/O operations on highly associative large memory stores are a good
example, I think. Do you want to silently cache huge amounts of data?
How do you handle object copy semantics?
What do you mean by sentence #1?

I inferred from your question and your code that you are seeking a
unified caching strategy. My intent was to discourage you by giving
an example of two operations that typically are best cached in
different ways.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top