6

Here is a concrete minimal example to formulate my question :

In small ball game, you have a physics engine that moves the objects regularly:

void move(set< PhysicalObject* > objets, Duration t)

And that engine can use user defined behaviour when a collision happens (using a strategy class). For instance, default strategy is to update objects directions, but you can provide it with a custom strategy class that kills objects according to some specific rules.

void update_after_collision(DerivedObject* a, DerivedObject* b)

In order to implement new behaviour during a collision, I have some specific derived classes (they have additional attributes/methods corresponding to their lifetime, etc.)

The problem is: the engine calls the update_after_collision strategy, hence I can't use my derived class is this strategy without using a visitor pattern or a type cast. Note that the engine only knows about the base class, not the derived ones.

Is there a way to avoid it? What is the standard approach to look at?

Is another programming paradigm better for this particular case?

EDIT : Code is written in C++

  • 1
    In my opinion, each of your objects should implement a HandleCollision method on an ICollidable interface that takes the same two arguments: mass and velocity of the colliding object. There are a few reasons why I think this, but the primary reason is that your update_after_collision method appears to know too much about each object. The object itself should decide whether it is dead after the collision, not some outside method. – Robert Harvey Jan 18 '16 at 22:00
  • 2
    You need to dispatch dynamically here, so a visitor or a type cast seems adequate. If you are asking for alternatives, all I can think of is the following (which could quickly become impractical): separate your instances into different buckets according to their type (at creation time) and change the update_after_collision callback (it is a callback, isn't it?) when computing the update function for each set of objects. Is there a reason you want to avoid having a visitor? – coredump Jan 18 '16 at 22:06
  • @RobertHarvey : (1) if the physic engine can't know about "object dying" so I still would have to do a cast somewhere. Do you see a workaround ? – Julien__ Jan 18 '16 at 22:11
  • 1
    @Julien__: A dead object should still be able to communicate its dead state to the physics engine in some generic way; i.e. IKillable. – Robert Harvey Jan 18 '16 at 22:32
  • 1
    Is is true that you have to handle two different types at once? Which is to say you can't call a.update_after_collision(b); /*and*/ b.update_after_collision(a /*or some clone of the original a*/);? The simpler dispatch should fit OOP better. Just checking... – Erik Eidt Jan 19 '16 at 1:03
3

What you have here is a typical use-case of runtime multiple-dispatch, and depending on the actual object-oriented language you intend to use, this is either built-in or requires some work. I am sorry this answer cannot be more precise, but this depends largely on the actual programming language.

Assuming a Java-esque language, you could quickly devise a custom dispatch method: a simple organisation of "classes" in an enumerated type can be enough at first and quite easy to modify. Each object holds a type tag indicating which types it belongs to.

Your collision method can hold a square matrix of specialized callbacks for each combination of types. In pseudo-code:

collisions[from.tag][to.tag]

... refers to the method you need to call with the given from and to objects. You can extend your set of tags, but this requires a recompilation phase. But binding tags to effective methods can be done at runtime while debugging, if you want.

If you want to introduce inheritance, this becomes a little more involved: imagine there is no specific method for a tag T (an empty cell in the collisions matrix), you should fall back to its parent type P(T) (assuming single-inheritance). For that you could have a parent member inside each of your enum value.

For C++, have a look at Open Multi-Methods for C++ from Stroustrup et al.

  • Thanks for you answer and for the link (+1). Still, I'm looking for something different : extracting subclasses, using composition, etc. in order to avoid such an approach. If multiple dispatch / multimethods in C++ interest you, and if implementing a visitor pattern doesn't bother you, have a look at that library (it's in french, but code should be sefl explanatory) : bitbucket.org/Gauss_/library-multiple-dispatch-in-cpp/src/… – Julien__ Jan 19 '16 at 10:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.