By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,294 Members | 2,588 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,294 IT Pros & Developers. It's quick & easy.

What is a good idiom for handling a lazy object?

P: n/a
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;
};
Jul 22 '05 #1
Share this Question
Share on Google+
12 Replies


P: n/a
Siemel Naran wrote:
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.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #2

P: n/a
"Siemel Naran" <Si*********@REMOVE.att.net> wrote...
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
Jul 22 '05 #3

P: n/a
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message news:28-
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.
Jul 22 '05 #4

P: n/a
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:p2Hec.123685$K91.338613@attbi_s02...
"Siemel Naran" <Si*********@REMOVE.att.net> wrote...

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


Thanks, good catch!
};
(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.


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.
Jul 22 '05 #5

P: n/a
Siemel Naran wrote:
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:p2Hec.123685$K91.338613@attbi_s02...
"Siemel Naran" <Si*********@REMOVE.att.net> wrote...
void calculate() const { z = x+y; calculated = true; }


Thanks, good catch!


Yup. That had me a bit confused.
> (2)
>
> class Answer {
> virtual ~Answer();
> };
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.
> class Lazy : public Answer {
> public:
> Lazy(double x, double y) : x(x), y(y) { }
> private:
> friend class Eval;
> double x;
> double y;
> };
You've exposed Lazy::x and Lazy::y to Eval.
> class Eval : public Answer {
> public:
> Eval(const Lazy& lazy) : z(calculate(lazy))
I believe you meant to put a semicolon at the end of the above line. No?
> double operator()() const { return z; } This returns Eval::z no matter what. No magic involved, right?
> private:
> double z;
> static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
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;
> }; > 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));
> }
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.
> const Eval * eval = static_cast<const Eval *>(answer.get());
> assert(eval);
I don't like assert. But then I think checked exceptions are a good thing.
Why did you use it here?
> return (*eval)();
> }
> private:
> mutable boost::shared_ptr<Answer> answer;
> };

[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/...anceof-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.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #6

P: n/a
On Mon, 12 Apr 2004 05:48:00 GMT, "Siemel Naran"
<Si*********@REMOVE.att.net> wrote:
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
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #7

P: n/a
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:p2Hec.123685
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.


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;
};
Jul 22 '05 #8

P: n/a
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:3O********************@speakeasy.net...
Siemel Naran wrote:
Eval(const Lazy& lazy) : z(calculate(lazy))


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


Actualy { }

> double operator()() const { return z; } This returns Eval::z no matter what. No magic involved, right?


Right.
> private:
> double z;
> static void calculate(const Lazy& lazy) { return lazy.x+lazy.y; }
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;

> 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));
> }
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.
> const Eval * eval = static_cast<const Eval *>(answer.get());
> assert(eval);

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.

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


Huh?

Jul 22 '05 #9

P: n/a
"tom_usenet" <to********@hotmail.com> wrote in message
news:l7********************************@4ax.com...
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?
Jul 22 '05 #10

P: n/a
"Siemel Naran" <Si*********@REMOVE.att.net> wrote in message news:<k4*******************@bgtnsc05-news.ops.worldnet.att.net>...
What is a good idiom for handling a lazy object?
I think that accessor functions are necessary and sufficient.
I see 2 good possibilities. <snipped code> 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
Jul 22 '05 #11

P: n/a
"anon luker" <ha*********@yahoo.com> wrote in message
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?
Jul 22 '05 #12

P: n/a
"Siemel Naran" <Si*********@REMOVE.att.net> wrote in message news:<US********************@bgtnsc04-news.ops.worldnet.att.net>...
"anon luker" <ha*********@yahoo.com> wrote in message
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.


Google "memoize" - Results 1 - 30 of about 13,000 for memoize. (0.38
seconds)
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?


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


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.
Jul 22 '05 #13

This discussion thread is closed

Replies have been disabled for this discussion.