Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Between static & dynamic polymorphism...

4 views
Skip to first unread message

rwf_20

unread,
Nov 16, 2005, 11:29:14 AM11/16/05
to
I just wanted to throw this up here in case anyone smarter than me has
a suggestion/workaround:

Problem:

I have a classic producer/consumer system which accepts 'commands' from
a socket and 'executes' them. Obviously, each different command (there
are ~20 currently) has its own needed functionality. The dream goal
here would be to remove all knowledge of the nature of the command at
runtime. That is, I don't want ANY switch/cases or if/elses to
determine what command has been received, etc:

1. Accept command from socket.
2. Create generic 'command' object with command data.
3. Call 'execute' on command object.
4. Command-specific code runs.

So, there's two obvious ways that are _close_:

Using static polylmorphism:

template <unsigned long commandCode>
class base_command {
void execute();
....
};

// command 1
void base_command<1>::execute() {
...command 1 specific code...
}
void base_command<2>::execute() {
...command 2 specific code...
}

int main() {
unsigned long commandCode = //read command in somehow
base_command<commandCode>().execute(); //obviously doesn't work
because the compiler doesn't know 'commandCode' at compile-time
}


Using dynamic polymorphism:

class base_command {
virtual void execute() = 0;
};

class command_1 : public base_command {
virtual void execute() {
...command 1 specific code...
}
};

class command_2 : public base_command {
... etc...
};

int main() {
unsigned long commandCode = // read command in somehow
base_command* c = // some logic to determine subclass from (huge
switch/case)
}


So, I'd love to use static polymorphism, but I'm fairly certain this
can't and never will happen, due to no compile-time knowledge of the
command code. I'm currently implementing the dynamic method, but I
HATE the huge switch/case needed to determine command type. The
executable size should be the same in all cases, but what I'm really
looking for is a) cleanliness and b) efficiency. I'm on an embedded
system, so using polymorphism makes me sick to my stomach. But, I
guess it's either that or one class with an enormous if/else.

I've got some other crazy half-ideas like a map of constructor function
objects indexed by command code (boost probably has something nutty
that might half-support this). But for the most part I think I'm
stuck.

Unless anyone has any thoughts...


Thanks,
Ryan

Jonathan Mcdougall

unread,
Nov 16, 2005, 11:39:24 AM11/16/05
to
rwf_20 wrote:
> I just wanted to throw this up here in case anyone smarter than me has
> a suggestion/workaround:
>
> Problem:
>
> I have a classic producer/consumer system which accepts 'commands' from
> a socket and 'executes' them. Obviously, each different command (there
> are ~20 currently) has its own needed functionality. The dream goal
> here would be to remove all knowledge of the nature of the command at
> runtime. That is, I don't want ANY switch/cases or if/elses to
> determine what command has been received, etc:

Look up "object factory" on the web and get Modern C++ Design by
Alexandrescu. Or simply define a std::map<id, function_pointer>.


Jonathan

Jeremy Jurksztowicz

unread,
Nov 16, 2005, 11:56:58 AM11/16/05
to
Alternatively use boost::function<void (param_t)>.

Example:

typedef boost::function<void (void)> ConsumerCommand;
ConsumerCommand cmd;
bool gotIt = consumerQueue.getNext(cmd);
if(gotIt) cmd();

werasm

unread,
Nov 16, 2005, 12:25:38 PM11/16/05
to

rwf_20 wrote:
> I just wanted to throw this up here in case anyone smarter than me has
> a suggestion/workaround:
>


I don't know whether I'm smarter, thats (smarter in terms of what)...
but

You need to abstract dynamic and static polymorphism from each other.
You want to be able to use dynamic polymorphism to execute via one
interface, but static polymorphism to call something specific (I don't
know whether this makes sense).

You can never bind the sender of your command to a receiver type, as it
may want to send msgs to arbitrary receivers. For this reason, your
base should use dynamic polymorphism (I'll be brief).

struct BaseCmd
{
void execute() = 0;
BaseCmd* clone() const = 0; //I know of better clone implementations
:-)
};

class Client //Going to call Cmd.execute
{
void associate( const BaseCmd& cmd ){ cmd_ = cmd.clone(); }
//...
BaseCmd* cmd_;
};

template <class T>
class MyCmd : public BaseCmd
{
//Implements execute.
};

Now we win by creating 1 command that represents all type T's, but
Client is oblivious as the BaseCmd is not type dependent. Winning both
ways by abstracting dynamic and static parts.

For more information, you can also refer to Herb Sutters article
"Elegant function call wrappers".

Kind regards,

Werner

rwf_20

unread,
Nov 16, 2005, 12:57:34 PM11/16/05
to
Thanks for the suggestions, all.

I've got something along these lines now. While not a complete
solution, I do like the top-level syntax, which is the general goal.

// base_command.h
#include <boost/function.hpp>

typedef boost::function<void (void)> exeFunction;

std::map<unsigned long, exeFunction> constructorMapG;

#define CMDCODE_ACQUIRE 0x1
#define CMDCODE_ABORT 0x3
#define CMDCODE_LASERTEST 0x18
#define CMDCODE_FIRELASER 0x19

template <unsigned long commandCode>
class base_command {

public:
static void execute() { printf("in base_execute()\n"); }
};

void base_command<CMDCODE_FIRELASER>::execute() {
printf("in fire_laser execute()\n");
}
void base_command<CMDCODE_ACQUIRE>::execute() {
printf("in acquire() execute()\n");
}
void base_command<CMDCODE_ABORT>::execute() {
printf("in abort() execute()\n");
}
void base_command<CMDCODE_LASERTEST>::execute() {
printf("in laser_test() execute()\n");
}

void registerConstructors() {
constructorMapG[CMDCODE_ABORT] = base_command<CMDCODE_ABORT>::execute;
constructorMapG[CMDCODE_ACQUIRE] =
base_command<CMDCODE_ACQUIRE>::execute;
constructorMapG[CMDCODE_LASERTEST] =
base_command<CMDCODE_LASERTEST>::execute;
constructorMapG[CMDCODE_FIRELASER] =
base_command<CMDCODE_FIRELASER>::execute;
}

typedef std::map<unsigned long, exeFunction>::const_iterator mapItr;

exeFunction getMeAnExecute(const unsigned long code) {
mapItr m = constructorMapG.find(code);
if (m != constructorMapG.end()) return (*m).second;
else // throw exception denoting invalid command
}


int main() {
unsigned long cmdCode = // get command from socket
getMeAnExecute(cmdCode)();
}

Any more thoughts on this or another solution are welcome.

Thanks,
Ryan

Puppet_Sock

unread,
Nov 16, 2005, 1:08:38 PM11/16/05
to
rwf_20 wrote:
> I have a classic producer/consumer system which accepts 'commands' from
> a socket and 'executes' them. Obviously, each different command (there
> are ~20 currently) has its own needed functionality. The dream goal
> here would be to remove all knowledge of the nature of the command at
> runtime. That is, I don't want ANY switch/cases or if/elses to
> determine what command has been received, etc:
[snip]

Ok, the discussion that followed this was great, and I will need to
be learning from that.

I'm just wondering, is 20 entries in a switch/case really that
horrible?
For that matter, would 100 entries be really that horrible? The time
spent by your code looking up the correct entry in a switch/case is
not going to be a large fraction of total run time. The cases can
easily
be made quite brief by making them function calls or some such.
Switch/case methods are easy to design, easy to document, easy to
debug, easy to maintain.

Especially if you use some variation of the standard map so that
you don't need to worry about converting the incoming msgs to
integers.

So, I'm wondering what it is about switch/case that bothers you so
much.
It makes me think I must be missing something important.
Socks

rwf_20

unread,
Nov 16, 2005, 1:20:38 PM11/16/05
to
> So, I'm wondering what it is about switch/case that bothers you so much.
> It makes me think I must be missing something important.

Not really, no. My problem boils down to preference, really. What you
say is true; a 100 switch/case block is not a big deal at all. In
fact, this is what I've had previously in my scenario.

What motivated my post is that, for N commands, the switch case is at
least N extra lines of specialized code just to determine which one of
N specialized functions to call! Sure, you can wrap it up cleanly,
etc...but I've already written T::execute() N times -- I felt I
deserved some way to avoid creating T in N different ways :). What
sucks is that there is _almost_ a way, if you could only instantiate a
template with a variable (I know, I know, this is impossible(?)).

Ryan

Jonathan Mcdougall

unread,
Nov 16, 2005, 1:29:40 PM11/16/05
to

rwf_20 wrote:
> > So, I'm wondering what it is about switch/case that bothers you so much.
> > It makes me think I must be missing something important.
>
> Not really, no. My problem boils down to preference, really. What you
> say is true; a 100 switch/case block is not a big deal at all. In
> fact, this is what I've had previously in my scenario.

IMO, event a single test on an object identity is a big deal. It should
be avoided when possible.

> What motivated my post is that, for N commands, the switch case is at
> least N extra lines of specialized code just to determine which one of
> N specialized functions to call! Sure, you can wrap it up cleanly,
> etc...but I've already written T::execute() N times -- I felt I
> deserved some way to avoid creating T in N different ways :).

The problem here, I guess, is not the hierarchy, but the object
creation. You get an ID at runtime and need to create the appropriate
object. One you get the object, it is only a matter of calling a
virtual function.

Creating the object is usually achieved using a map of id=>creator. The
creator can be a function, another clonable object or whatever. Then,
you must make sure every creator has a unique id and finally register
them all in the map.

> What
> sucks is that there is _almost_ a way, if you could only instantiate a
> template with a variable (I know, I know, this is impossible(?)).

That does not make sense. It's like trying to have the address of a
variable as a compile-time constant. A variable is a run-time entity. A
template is a compile-time entity. At run-time, no "template" exist,
only concrete functions. At compile-time, no "variable" exist, only
names. Templates are a way in C++ to "automatically" create a family of
functions at compile-time. It's syntactic sugar.


Jonathan

Kai-Uwe Bux

unread,
Nov 16, 2005, 1:36:26 PM11/16/05
to
rwf_20 wrote:

[snip]


>
> So, I'd love to use static polymorphism, but I'm fairly certain this
> can't and never will happen, due to no compile-time knowledge of the
> command code. I'm currently implementing the dynamic method, but I
> HATE the huge switch/case needed to determine command type. The
> executable size should be the same in all cases, but what I'm really
> looking for is a) cleanliness and b) efficiency. I'm on an embedded
> system, so using polymorphism makes me sick to my stomach. But, I
> guess it's either that or one class with an enormous if/else.

You can trick a template into generating the code for the if/else:

#include <iostream>


template <unsigned long N>
void print ( void ) { std::cout << N << '\n'; }

struct eval {

typedef unsigned long enum_type;
static enum_type const first = 0;
static enum_type const last = 50;

typedef int value_type;

template < unsigned long N >
static
int function ( void ) {
print<N>();
return 0;
}

};

template < typename eval >
struct tpl_bin_search {

typedef typename eval::enum_type Enum;

template < Enum first, Enum last >
static
typename eval::value_type alg ( Enum val ) {
if ( first == last ) {
return( eval::template function<first>() );
}
if ( (Enum)( first + ( last-first )/2 ) < val ) {
return( tpl_bin_search< eval >::template
alg< (Enum)( last - ( last-first )/2), last >( val ) );
} else {
return( tpl_bin_search< eval >::template
alg< first, (Enum)( first + ( last-first )/2) >( val ) );
}
}

};

template < typename eval >
typename eval::value_type bin_search ( typename eval::enum_type val ) {
return( tpl_bin_search< eval >::template
alg< eval::first, eval::last >( val ) );
}

int main ( void ) {
bin_search<eval>( 4 );
}


Best

Kai-Uwe Bux

rwf_20

unread,
Nov 16, 2005, 1:45:07 PM11/16/05
to
> Creating the object is usually achieved using a map of id=>creator. The
> creator can be a function, another clonable object or whatever. Then,
> you must make sure every creator has a unique id and finally register
> them all in the map.

Yes, this is what I have.

> That does not make sense. It's like trying to have the address of a
> variable as a compile-time constant. A variable is a run-time entity. A
> template is a compile-time entity. At run-time, no "template" exist,
> only concrete functions. At compile-time, no "variable" exist, only
> names. Templates are a way in C++ to "automatically" create a family of
> functions at compile-time. It's syntactic sugar.

Yes, I understand why it can't work. As the subject implies, a
completely clean solution would lie somewhere in between static &
dynamic. I'm sure this could be achieved with a variety of compiler
hacks, but I'm also sure the results would blur the (measurable)
benefits of each pure method.

Ryan

Jim Langston

unread,
Nov 16, 2005, 9:12:07 PM11/16/05
to
"rwf_20" <rfr...@gmail.com> wrote in message
news:1132158554.7...@g44g2000cwa.googlegroups.com...

Sounds like a map problem to me. Build a map with the key being your
commands, and the object being a factory for the object to be created for
that command. Receive the command, find it in the map, build the object,
run execute. It would be run time polymorphism though, but no case
statements involved, just building the map.

Although when it comes down to it, one line to build each map object, one
line for each cast statement. Somehow you have to associate the command
with the object to be created, and this will take at least one line of code
per command/object.


werasm

unread,
Nov 17, 2005, 3:06:54 AM11/17/05
to

rwf_20 wrote:
> Thanks for the suggestions, all.
>
> I've got something along these lines now. While not a complete
> solution, I do like the top-level syntax, which is the general goal.
>
> // base_command.h
> #include <boost/function.hpp>

Why are you includin

Hi Ryan,

You have to ask yourself how this would have looked if you implemented
it using switch case style. The problem with your problem is that the
code is not known statically. For this reason you have to use either a
switch, or a data-structure like a map to do what you want to do. You
don't seem to gain anything wrt. scalability, and you've certainly
compromised efficiency. I therefore don't see any benefits whatsoever
when looking at your solution.

The fact is, if you want to gain flexibility, you will loose some
efficiency. The question is, how much efficiency are you willing to
loose. Is scalability so important that you are willing to compromise
efficiency. On the other hand, is efficiency so important that you
don't want to make it scalable? By steering away from switch/case style
programming in the case here above, you've seemingly made things more
complicated, less efficient (using map instead of switch) and less
scalable (to add one additional case, you are required to specialize a
member function and add some code to register this for each case.)

IMHO a bad solution :). Face it, your commandCode is not know at
compile time. Therefore using static polymorphism to the extent to
which you want to, is not viable.

Kind regards

Werner

rwf_20

unread,
Nov 17, 2005, 2:22:33 PM11/17/05
to
> The fact is, if you want to gain flexibility, you will loose some
> efficiency.

Surely, you're right Werner. It seems the holy grail of cleanliness &
efficiency are not completely obtainable here. The best way, as far as
I can tell, would be a mix. Specialize the execute() template for each
command. Then, call the appropriate specialization in the switch-case.
This would eliminate the dynamic polymophism overhead with similar
code size.

I'm basically doing this now, but I'm just using the map because I like
the idea of calling a generic function at the top level. So it seems
the tradeoff is a map find vs. a switch/case.

Am I missing something?

Ryan

mlimber

unread,
Nov 17, 2005, 2:58:37 PM11/17/05
to

Ryan, I recently solved this same problem. I used an object factory
from chapter 8 of _Modern C++ Design_, as Jonathan also suggested
above. The factory is intended to allow extensibility and cleanliness
of dynamic polymorphism while avoiding the switch statements that you
rightly dread. To use the factory (which can be downloaded free from
http://sourceforge.net/projects/loki-lib), one simply associates an ID
with each command, registers that ID and the relevant creation function
with the factory, and supplies that ID to the factory when it's time to
create the object. Compare:

struct Cmd
{
virtual void Execute() = 0;
virtual void Deserialize( const void*, unsigned ) = 0;
};

// IDs
enum CmdID { CMD_1, CMD_2 /* etc. */ };

struct Cmd1 : Cmd
{
static const CmdID ID = CMD_1;
static Cmd* Create() { return new Cmd1; }

void Execute() { /* Do something */ }
void Deserialize( const void*, unsigned ) { /* init members */ }
// ...
};

struct Cmd2 : Cmd
{
static const CmdID ID = CMD_2;
static Cmd* Create() { return new Cmd2; }

void Execute() { /* Do something else */ }
void Deserialize( const void*, unsigned ) { /* init members */ }
// ...
};

// Our factory
Loki::Factory<Cmd, int> cmdFactory;

// Register each concrete class with the factory
const bool reg1 = cmdFactory.Register( Cmd1::ID, Cmd1::Create );
const bool reg2 = cmdFactory.Register( Cmd2::ID, Cmd2::Create );

// Get a new command
Cmd* ConvertSocketDataToCmd(
const void* const data,
const unsigned size )
{
// Validate fn params
assert( data && size );

// First int-sized datum is always the ID
const int id = *static_cast<const int*>( data );

// Get the correct command
Cmd* const cmd = cmdFactory.CreateObject( id );

// Fill in the cmd
cmd->Deserialize( data, size );

return cmd;
}


I actually use much of the same code (i.e. same source files) on both
sides of my communication barrier. The producer simply implements
Cmd::Execute() to send the command across, while the consumer
implements it to perform the desired action on the other side of the
barrier. (The real thing also has serialization facilities, responses
to the commands, etc., but you get the idea.)

Compare also the FAQ on serialization
(http://www.parashift.com/c++-faq-lite/serialization.html) and the
Boost serialization library
(http://boost.org/libs/serialization/doc/index.html).

Cheers! --M

rwf_20

unread,
Nov 17, 2005, 3:10:49 PM11/17/05
to
mlimber wrote:
> Ryan, I recently solved this same problem. I used an object factory
> from chapter 8 of _Modern C++ Design_, as Jonathan also suggested
> above. The factory is intended to allow extensibility and cleanliness
> of dynamic polymorphism while avoiding the switch statements that you
> rightly dread. To use the factory (which can be downloaded free from
> http://sourceforge.net/projects/loki-lib), one simply associates an ID
> with each command, registers that ID and the relevant creation function
> with the factory, and supplies that ID to the factory when it's time to
> create the object.

This is almost exactly what I'm doing now. But, instead of creating a
derived class for each command, I'm simply specializing execute() in
the base class. So, instead of registering each Cmd object with the
factory, I'm registering each specialization of execute() in a map.
Plus, it's not clear to me how it could be any slower (other than my
writing it as opposed to Alexandrescu) -- it seems my method trades all
the dynamic overhead for a map lookup.

Thanks for the input,
Ryan

mlimber

unread,
Nov 17, 2005, 4:23:33 PM11/17/05
to

It won't likely be slower unless you call execute many times or much
faster since you're simply trading a map lookup at the creation for one
at the execution. The inefficiency of a virtual call is over-hyped in
some circles (I work in an embedded environment, too) and, in practice,
is often dwarfed and rendered insignificant by the body of the virtual
function itself.

My preference would be to go for the most idiomatic, understandable,
and maintainable code, and IMHO, the funky stuff is better hidden at
the creation than in the operation of the class. For that reason, I
chose the factory approach.

Cheers! --M

0 new messages