Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Looking for right idiom

Reply
Thread Tools

Looking for right idiom

 
 
Johannes Bauer
Guest
Posts: n/a
 
      08-23-2012
Hi group,

I'm looking for a OO idiom and currently just have a knot in my brain.
I'll explain what the result should be and hopefully somebody can help
me out.

Let's assume I have a class A which has a method setValue(int, int).
Let's further assume that the operation is quite expensive (for example,
think of a database commit). However, in order to keep complexity low,
consecutive setValue() operations can be combined. Assume for example that

a.setValue(w, x)
a.setValue(y, z)

would be equivalent to

a.setValue((w ^ y) * z, z - x)

i.e. the expensive setValue() operation would be executed only once at
the cost of cheap arithmetic operations.

The way I would like this to behave is have the setValue() operation
return some kind of cascadable object that does a "commit" when the last
operation has finished. In other words, it should be possible to:

a.setValue(w, x).setValue(y, z)

(and cascade them infinitely) so that the operands are first all fully
evaluated and then there's only one commit action.

How is this possible with the least overhead in times of runtime
complexity? I don't really have any good ideas here. Would be great if
you could help me out.

Best regards,
Joe


--
>> Wo hattest Du das Beben nochmal GENAU vorhergesagt?

> Zumindest nicht öffentlich!

Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <hidbv3$om2$(E-Mail Removed)>
 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      08-23-2012
On 8/23/2012 6:33 AM, Johannes Bauer wrote:
> I'm looking for a OO idiom and currently just have a knot in my brain.
> I'll explain what the result should be and hopefully somebody can help
> me out.
>
> Let's assume I have a class A which has a method setValue(int, int).
> Let's further assume that the operation is quite expensive (for example,
> think of a database commit). However, in order to keep complexity low,
> consecutive setValue() operations can be combined. Assume for example that
>
> a.setValue(w, x)
> a.setValue(y, z)
>
> would be equivalent to
>
> a.setValue((w ^ y) * z, z - x)
>
> i.e. the expensive setValue() operation would be executed only once at
> the cost of cheap arithmetic operations.
>
> The way I would like this to behave is have the setValue() operation
> return some kind of cascadable object that does a "commit" when the last
> operation has finished. In other words, it should be possible to:
>
> a.setValue(w, x).setValue(y, z)
>
> (and cascade them infinitely) so that the operands are first all fully
> evaluated and then there's only one commit action.
>
> How is this possible with the least overhead in times of runtime
> complexity? I don't really have any good ideas here. Would be great if
> you could help me out.


This is untested code. Typed in off the top of my head.

struct A {
struct SetterProxy {
SetterProxy(int, int, A&);
SetterProxy& setValue(int,int);
~SetterProxy();
private:
A& m_owner;
// other members needed to keep the cache
};
friend SetterProxy; // need this to call 'perform'
SetterProxy setValue(int,int);

private:
void performLongSetOperation(/* args */);
};

A::SetterProxy::SetterProxy(int x, int y, A& owner)
: m_owner(owner)
{
/* other stuff for setting up cache */
}

void A::SetterProxy::~SetterProxy()
{
m_owner.performLongSetOperation(/* whatever */);
}

A::SetterProxy A::setValue(int x, int y)
{
return SetterProxy(x, y, *this);
}

A::SetterProxy& A::SetterProxy::setValue(int x, int y)
{
// add 'x' and 'y' to the cache...
return *this;
}

void A:erformLongSetOperation(/* args */)
{
// ... whatever
}

Can you fill in the rest?

V
--
I do not respond to top-posted replies, please don't ask
 
Reply With Quote
 
 
 
 
Öö Tiib
Guest
Posts: n/a
 
      08-23-2012
On Thursday, August 23, 2012 1:33:19 PM UTC+3, Johannes Bauer wrote:
> Let's assume I have a class A which has a method setValue(int, int).
> Let's further assume that the operation is quite expensive (for example,
> think of a database commit). However, in order to keep complexity low,
> consecutive setValue() operations can be combined. Assume for example that
>
> a.setValue(w, x)
> a.setValue(y, z)
>
> would be equivalent to
>
> a.setValue((w ^ y) * z, z - x)
>
> i.e. the expensive setValue() operation would be executed only once at
> the cost of cheap arithmetic operations.


Ok, the idiom is "laziness". Typically when you traverse the net you find examples of lazy initialization but anything can be made lazy.

Make your "value setter" to collect the not yet done work (or partially done work) until user explicitly calls commit(). You may want to check that the work has been actually completed in destructor. If the destructor then commit()'s itself or complains (avoid exceptions there) about a bug is matterof how explicit interface you like.


Chaining is usually assumed to be just a syntax convenience thing and done by returning *this from setValue(). So:

result = a.setValue(w, x).setValue(y, z).commit();

Is just convenient way to say:

a.setValue(w, x);
a.setValue(y, z);
result = a.commit();
 
Reply With Quote
 
Johannes Bauer
Guest
Posts: n/a
 
      08-23-2012
On 23.08.2012 13:49, Victor Bazarov wrote:

> This is untested code. Typed in off the top of my head.


Thank you very much, Victor. It worked perfectly and is just what I was
looking for (my solutions were MUCH more clumsy). gcc actually doesn't
complain when the friend declaration is missing, are inner classes
always friends or must the declaration be there?

I especially like what gcc does with the code. On x86-64 with gcc 4.6.2
with -O3 the surrogate object is completely optimized away and just the
actual "perform" tasks are done. This is wonderful! Fantastic.

Here's a link to your code (I merely filled in the blanks and renamed
some stuff and inserted logging in case anyone else is interested):

http://pastebin.com/ghUrmNpi

In case this doesn't get archived, I'll also post the full source code
below this message.

Thank you again for giving me the correct direction. I'll implement this
right now

Best regards,
Joe


Modified code of Victor (same as Pastebin):
#include <iostream>

//#define LOGGING

volatile int fooVar;

class MyObject {
private:
class SetterProxy {
private:
MyObject &owner;
int xCache, yCache;

public:
SetterProxy(int aX, int aY, MyObject &aOwner) : owner(aOwner) {
#ifdef LOGGING
std::cerr << "Proxy Construct " << aX << " / " << aY << std::endl;
#endif
xCache = aX;
yCache = aY;
}

SetterProxy& setValue(int aX, int aY) {
#ifdef LOGGING
std::cerr << "Proxy Set " << aX << " / " << aY << std::endl;
#endif
xCache += aX;
yCache += aY;
return *this;
}

~SetterProxy() {
owner.performLongSetOperation(xCache, yCache);
}
};

void performLongSetOperation(int aX, int aY) {
#ifdef LOGGING
std::cerr << "Perform: " << aX << " / " << aY << std::endl;
#endif
fooVar = aX + aY;
}

public:
SetterProxy setValue(int aParam1, int aParam2) {
return SetterProxy(aParam1, aParam2, *this);
}
};


int main(int argc, char **argv) {
MyObject obj;
obj.setValue(1, 2);
obj.setValue(1, 2).setValue(10, 20);
obj.setValue(1, 2).setValue(10, 20).setValue(100, 200);
obj.setValue(1, 2).setValue(10, 20).setValue(100, 200).setValue(1000,
2000);
obj.setValue(1, 2).setValue(10, 20).setValue(100, 200).setValue(1000,
2000).setValue(argc, 9);
return 0;
}



--
>> Wo hattest Du das Beben nochmal GENAU vorhergesagt?

> Zumindest nicht öffentlich!

Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <hidbv3$om2$(E-Mail Removed)>
 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      08-23-2012
On 8/23/2012 9:12 AM, Johannes Bauer wrote:
> [..]
> void performLongSetOperation(int aX, int aY) {
> #ifdef LOGGING
> std::cerr << "Perform: " << aX << " / " << aY << std::endl;

.. ^^^^
> #endif
> fooVar = aX + aY;

.. ^^^^
> }
> [..]




V
--
I do not respond to top-posted replies, please don't ask
 
Reply With Quote
 
Jorgen Grahn
Guest
Posts: n/a
 
      08-23-2012
On Thu, 2012-08-23, Johannes Bauer wrote:
> Hi group,
>
> I'm looking for a OO idiom and currently just have a knot in my brain.
> I'll explain what the result should be and hopefully somebody can help
> me out.
>
> Let's assume I have a class A which has a method setValue(int, int).
> Let's further assume that the operation is quite expensive (for example,
> think of a database commit). However, in order to keep complexity low,
> consecutive setValue() operations can be combined. Assume for example that
>
> a.setValue(w, x)
> a.setValue(y, z)
>
> would be equivalent to
>
> a.setValue((w ^ y) * z, z - x)
>
> i.e. the expensive setValue() operation would be executed only once at
> the cost of cheap arithmetic operations.
>
> The way I would like this to behave is have the setValue() operation
> return some kind of cascadable object that does a "commit" when the last
> operation has finished. In other words, it should be possible to:


I suspect that much of the time, it's better to accept that this /is/
something expensive, and expose that fact in the interface. I.e. have
an explicit a.commit() somewhere.

(Note that I'm not saying it's /always/ a bad idea to make it
automatic. File I/O for example -- it would not be convenient in the
general case to have to keep track of how much you've written so you
can flush at the right moment.)

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      08-24-2012
On 8/23/2012 5:51 PM, Jorgen Grahn wrote:
> On Thu, 2012-08-23, Johannes Bauer wrote:
>> Hi group,
>>
>> I'm looking for a OO idiom and currently just have a knot in my brain.
>> I'll explain what the result should be and hopefully somebody can help
>> me out.
>>
>> Let's assume I have a class A which has a method setValue(int, int).
>> Let's further assume that the operation is quite expensive (for example,
>> think of a database commit). However, in order to keep complexity low,
>> consecutive setValue() operations can be combined. Assume for example that
>>
>> a.setValue(w, x)
>> a.setValue(y, z)
>>
>> would be equivalent to
>>
>> a.setValue((w ^ y) * z, z - x)
>>
>> i.e. the expensive setValue() operation would be executed only once at
>> the cost of cheap arithmetic operations.
>>
>> The way I would like this to behave is have the setValue() operation
>> return some kind of cascadable object that does a "commit" when the last
>> operation has finished. In other words, it should be possible to:

>
> I suspect that much of the time, it's better to accept that this /is/
> something expensive, and expose that fact in the interface. I.e. have
> an explicit a.commit() somewhere.
>
> (Note that I'm not saying it's /always/ a bad idea to make it
> automatic. File I/O for example -- it would not be convenient in the
> general case to have to keep track of how much you've written so you
> can flush at the right moment.)


IOW, there is no general recommendation, is there? By the same token,
the 'Setter' could keep track of any sort of parameter of the operation
(like how many 'setValue' calls there have been, or how much time has
passed since it was created or since last 'flush') and perform that
lengthy operation (commit) according to some other heuristic.

V
--
I do not respond to top-posted replies, please don't ask
 
Reply With Quote
 
Öö Tiib
Guest
Posts: n/a
 
      08-24-2012
On Friday, August 24, 2012 3:22:49 AM UTC+3, Victor Bazarov wrote:
> On 8/23/2012 5:51 PM, Jorgen Grahn wrote:
> > I suspect that much of the time, it's better to accept that this /is/
> > something expensive, and expose that fact in the interface. I.e. have
> > an explicit a.commit() somewhere.
> >
> > (Note that I'm not saying it's /always/ a bad idea to make it
> > automatic. File I/O for example -- it would not be convenient in the
> > general case to have to keep track of how much you've written so you
> > can flush at the right moment.)

>
> IOW, there is no general recommendation, is there? By the same token,
> the 'Setter' could keep track of any sort of parameter of the operation
> (like how many 'setValue' calls there have been, or how much time has
> passed since it was created or since last 'flush') and perform that
> lengthy operation (commit) according to some other heuristic.


First it is good to be lazy and wait with implementing such laziness
until no one can call it a "preliminary optimization".
When done it may be still good to be more explicit but since the code
that uses the 'Setter' is already there the full automation will be
implemented. When it raises some other issues then some ways to 'flush'
manually will be added.
 
Reply With Quote
 
Jorgen Grahn
Guest
Posts: n/a
 
      08-24-2012
On Fri, 2012-08-24, Victor Bazarov wrote:
> On 8/23/2012 5:51 PM, Jorgen Grahn wrote:
>> On Thu, 2012-08-23, Johannes Bauer wrote:
>>> Hi group,
>>>
>>> I'm looking for a OO idiom and currently just have a knot in my brain.
>>> I'll explain what the result should be and hopefully somebody can help
>>> me out.
>>>
>>> Let's assume I have a class A which has a method setValue(int, int).
>>> Let's further assume that the operation is quite expensive (for example,
>>> think of a database commit). However, in order to keep complexity low,
>>> consecutive setValue() operations can be combined. Assume for example that
>>>
>>> a.setValue(w, x)
>>> a.setValue(y, z)
>>>
>>> would be equivalent to
>>>
>>> a.setValue((w ^ y) * z, z - x)
>>>
>>> i.e. the expensive setValue() operation would be executed only once at
>>> the cost of cheap arithmetic operations.
>>>
>>> The way I would like this to behave is have the setValue() operation
>>> return some kind of cascadable object that does a "commit" when the last
>>> operation has finished. In other words, it should be possible to:

>>
>> I suspect that much of the time, it's better to accept that this /is/
>> something expensive, and expose that fact in the interface. I.e. have
>> an explicit a.commit() somewhere.
>>
>> (Note that I'm not saying it's /always/ a bad idea to make it
>> automatic. File I/O for example -- it would not be convenient in the
>> general case to have to keep track of how much you've written so you
>> can flush at the right moment.)

>
> IOW, there is no general recommendation, is there? By the same token,
> the 'Setter' could keep track of any sort of parameter of the operation
> (like how many 'setValue' calls there have been, or how much time has
> passed since it was created or since last 'flush') and perform that
> lengthy operation (commit) according to some other heuristic.


Yes. My point was just that all this can be overkill, and make the
code less clear. Even though it's a good technique to be familiar
with.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Looking for the best way to translate an idiom Paul Moore Python 33 12-16-2008 10:43 AM
Dynamic Menu Items is not right aligned with Right to Left documen =?Utf-8?B?QmlzaG95?= ASP .Net 0 12-28-2006 11:39 AM
Tool to enable Right click on pages where Right click is disabled tsteinke@gmail.com Computer Support 4 08-28-2005 11:53 PM
Tool to right click image in windows explorer and rotate image right or left 90 degrees siliconpi Digital Photography 2 11-29-2004 12:56 PM
pass the right form input to the right control Tom ASP .Net 0 12-11-2003 03:07 AM



Advertisments