views:

180

answers:

5

I find myself using policies a lot in my code and usually I'm very happy with that. But from time to time I find myself confronted with using that pattern in situations where the Policies are selected and runtime and I have developed habbits to work around such situations. Usually I start with something like that:

class DrawArrays {
protected:
  void sendDraw() const;
};

class DrawElements {
public:
  void setIndices( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
protected:
  void sendDraw() const;
};

template<class Policy>
class Vertices : public Policy {
  using Policy::sendDraw();
public:
  void render() const;
};

When the policy is picked at runtime I have different choices of working around the situation.

Different code paths:

if(drawElements) {  
     Vertices<DrawElements> vertices;  
} else {   
     Vertices<DrawArrays> vertices;   
}

Inheritance and virtual calls:

class PureVertices {
public:
  void render()=0;
};

template<class Policy>
class Vertices : public PureVertices, public Policy {
  //..
};

Both solutions feel wrong to me. The first creates an umaintainable mess and the second introduces the overhead of virtual calls that I tried to avoid by using policies in the first place.

Am I missing the proper solutions or do I use the wrong pattern to solve the problem?

A: 

I don't see anything wrong with the first one - it doesn't look like an unmaintainable mess to me, although there's not enough code here to determine if there might be a better refactoring.

Ben Collins
See http://en.wikipedia.org/wiki/Policy-based_design and http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315 for an explanation of the inheritance.
pmr
Thanks for the reference.
Ben Collins
+4  A: 

Use the second version. Virtual calls are more expensive than static calls because they require an additional pointer lookup, but if "sendDraw" does any real drawing, you won't notice the difference. If you really have a performance problem later, use a profiler to find out where the problem is and fix it. In the (extremely unlikely) case that the virtual method call is actually a performance problem, you could try optimizing it using policies. Until then, write code that's most maintainable so you have development time left to optimize later.

Remeber: Premature optimization is the root of all evil!

nikie
I should have added that. In this particular example there probably will be a lot of calls to render and as many calls to sendDraw(). This could differ for every example. Sometimes there could be a lot of calls to the Policy methods or sometimes a lot of calls to host methods.
pmr
Not to mention that if there are more than two alternatives, the vtbl lookup will probably be faster than the branch. +1.
Billy ONeal
@pmr: even experts routinely misjudge performance bottlenecks. Never optimize code if you haven't *measured* that it (a) take a lot of time and that (b) the alternative will be faster. At least not if you're interested in writing fast code.
nikie
It's pretty much irrelevant that "there will probably be a lot of calls". "A lot" is meaningless. Will it be enough to make a difference performance-wise? Only way to find out is to measure it. (If you expect *millions* of calls per second, your gut feeling that performance is going to matter may be correct, but less than that, and it becomes much harder to guess)
jalf
A: 

In general, if you need behavior to vary at runtime you are going to have to pay some overhead cost for that, whether it be a switch/if statement or a virtual call. The question is how much runtime variance you need. If you're very confident you will only ever have a small number of types, then a switch statement may really be appropriate. Virtual calls give more flexibility for extending in the future, but you don't necessarily need that flexibility; it depends on the problem. That said, there's still a lot of of ways to implement your 'switch statement' or your 'virtual call'. Instead of a switch/if you could use the Visitor Pattern (more maintainable), and instead of virtual calls you could use function pointers (when it doesn't make sense for the class itself to specify the behavior that is invoked at runtime). Also, although I don't agree with everything the author says (I think he artificially makes his idea and OOP mutually exclusive) you might be interested in Data Oriented Programming, especially if you're working on rendering as your class names suggest.

Joseph Garvin
A virtual call is just a function pointer managed by the compiler. The virtual call, not the function pointer, is going to be better here.
Billy ONeal
@BillyONeal: I partially disagree. The function pointer can easily be replaced with a Functor and templatized so it can be inlined in most cases. This isn't neccessarily true for virtual functions.
pmr
@Pmr: Why not? If the virtual function call never changes (i.e. you have a reference to a base class), and the function pointer never changes then the compiler can perform the same optimizations in both cases because that's what virtual functions are -- function pointers. The only difference is you can't forget to initialize one in a constructor.
Billy ONeal
@BillyONeal: I'd like to see an example. My understanding is that passing in function pointers as arguments to a function/class-ctor is inherently a run-time operation and not open to any inline optimization by the compiler. Maybe I just don't see how you would do that without using functors and templates.
pmr
@pmr: Functors and templates are not function pointers. Function pointers can change at runtime, functors + templates cannot. You need behavior that changes at runtime so I assumed a template solution was not valid in your case. I'm saying if it's a function pointer versus a virtual call, the virtual call is preferable.
Billy ONeal
A: 

Why do you oppose virtual calls? Is the overhead really considerable for you? I think the code becomes more readable when you express what you want to do by writing an interface and different implementations instead of some unreadable templates.

Anyway, why do you inherit Vertices from Policy class? You already have it as a template argument. Looks like composition is more appropriate here. If you use inheritance, you can have just one non-template class Vertices and change its behaviour by passing different Policy objects - this is Strategy pattern.

class Policy {
public:
    void sendDraw() const =0;
}

class Vertices {
public:
    Vertices(Policy * policy) :
    : policy(policy)
    {
    }

    void render() {
        // Do something with policy->sendDraw();
    }
}
Dmitry Risenberg
See me comment to Ben Collins answer for an explanation of the inheritance. I'll modify the code to make the advantage more obvious (if you are familiar with the OpenGL calls ;) ).
pmr
A: 

If you aren't putting the draw calls into a display list then the array data will have to be copied out when it's drawn. (Either the caller blocks until the GPU is done, or the driver copies it out of the app memory to somewhere safe.) So the virtual function won't be an issue. And if you ARE putting them in a display list, then the virtual function won't be an issue, because it's only being set up the once.

And in any event, PCs do virtual calls very quickly. They're not free, it's true, but if drawing (say) thousands of sets of vertices per frame then an extra virtual function call per draw is highly unlikely to break the bank. Out of all the things to think about ahead of time, avoiding uses of a virtual function in the very sorts of situation that virtual functions are designed for is probably one of the less important ones. Unnecessarily-virtual functions are worth avoiding; genuinely useful virtual functions are innocent until proven guilty...

(Drawing more vertices per call and changing shader, shader constants, vertex format and render state settings less frequently are likely to pay greater dividends.)

brone