Advanced C# · OOP / API Design

Simulating Multiple Inheritance in C#

This content has permanently moved to http://benbowen.blog/post/simulating_multiple_inheritance_in_csharp/

Advertisements

4 thoughts on “Simulating Multiple Inheritance in C#

  1. Your code is interesting, but your example is terrible. You’ve completely misunderstood how an entity component system works (Don’t stress… lots of people get this wrong. Including Unity.)

    The point of components is not to add all this behavior to entities. In fact, components shouldn’t have behavior at all. Here’s how it should work. You have a group of ‘systems’. For example, the physics simulation system. Each system cares about and operates on a small set of types. For example, the physics system cares about rigid bodies. The physics system isn’t concerned with sounds, so it doesn’t even know that such components exist. When the game entity is created, it has some set of components. These components are given to each system. The physics system takes note of all the rigid bodies it sees, and stores them in it’s own internal state. The physics system never operates on entities. It doesn’t care what entities implement, or derive from, or what interface they can be casted to, or what component they happen to have. The physics system has a list of rigid bodies that it deals with and that’s it. And the rigid bodies are all very strongly typed.

    Once the components have been offered to each system, and each system has remembered the ones it is interested in, the entity can be forgotten by the rest of the system. It was just an ID and a list of components anyway.

    Lets look at some of the disadvantages of the methods you suggested.

    Polymorphism? Individual components are free to have an inheritance tree, and since they aren’t interfaces, they get virtual methods and everything. For example, maybe SphericalBody and MeshBody both inherit from RigidBody. The physics system works on RigidBodies, so SphericalBody and MeshBody blend in just fine.

    Adding fields to entities? Entities don’t have fields. Entities are just an ID number. Components have ID numbers. Incidentally, this is the implementation of IComponent: public interface IComponent {}

    Statically typed? Yes sir. The individual systems are free to store their components however they want (They don’t even have to use the component type to do it. How about sticking the data in a struct of arrays instead of an array of structs?)

    Thread safety? If two systems don’t care about the same component types, they are inherently thread safe. If they do share the same component type, the need for access control is confined to that specific component.

    In short: Stop trying to use components to add behavior to an entity class. Instead of trying to create a class that implements behavior X Y and Z for a single entity, create a system that implements behavior X for multiple entities, and another that implements behavior Y for multiple entities, etc.

    Sorry for shitting on your article. I’m exploring similar territory trying to implement duck typing in C# and I’m running into many of the same issues.

    Like

    1. Hi there!

      “The point of components is not to add all this behavior to entities. In fact, components shouldn’t have behavior at all. Here’s how it should work. You have a group of ‘systems’. For example, the physics simulation system. Each system cares about and operates on a small set of types. For example, the physics system cares about rigid bodies. The physics system isn’t concerned with sounds, so it doesn’t even know that such components exist.”

      This is actually exactly what I’m trying to model. The component extension methods (if we’re settled on the third approach) can be defined in the relevant spaces for each system. So the physics system can define ICollidable and all of the default implementation for it. Nothing else needs to care about the fact that an entity implements ICollidable; but if a special entity comes along that requires a more specialized implementation, we can write that (so long as we’ve incorporated the polymorphic behaviour).

      “The physics system takes note of all the rigid bodies it sees, and stores them in it’s own internal state. The physics system never operates on entities.”

      Again, the approach detailed here facilitates that. Although I do admit I used a global store of component state (e.g. the global ConditionalWeakTable), in reality this is only one way to attack the problem; and I wrote it this way for the sake of the example. You’re more than free to change where the data is stored- and that includes as a number of more localized flat arrays containing data pertinent to its owning system (i.e. the physics system containing a RigidBody[] or similar). In fact, for my own entity implementation, this is exactly what I’m doing.

      “[The physics system] doesn’t care what entities implement, or derive from, or what interface they can be casted to, or what component they happen to have. The physics system has a list of rigid bodies that it deals with and that’s it. And the rigid bodies are all very strongly typed.”

      And that’s fine- the physics system is free to work on the underlying data only when it comes to the dirty stuff. But having the interfaces in the entity system allows us to modify that data from the outside easier. Ultimately, there’s nothing forcing you to implement ‘PhysicsSystem.SetRigidBodyForEntity(entity, body)’ any different to ‘entity.SetRigidBody(body)’.

      “Once the components have been offered to each system, and each system has remembered the ones it is interested in, the entity can be forgotten by the rest of the system. It was just an ID and a list of components anyway.”

      Again, there’s nothing stopping you from implementing this with the MI example. We’ve already moved all the data off the entities (and put them in a ConditionalWeakTable)- you can partition it further quite easily.

      “Polymorphism? Individual components are free to have an inheritance tree, and since they aren’t interfaces, they get virtual methods and everything. For example, maybe SphericalBody and MeshBody both inherit from RigidBody. The physics system works on RigidBodies, so SphericalBody and MeshBody blend in just fine.”

      There’s nothing precluding this: If we have an extension method ‘public static void SetRigidBody(this ICollidable @this, RigidBody body)’, there’s no reason that same inheritance chain can’t be used.

      “Adding fields to entities? Entities don’t have fields. Entities are just an ID number. Components have ID numbers. Incidentally, this is the implementation of IComponent: public interface IComponent {}”

      Again, we’re not adding fields really, we’re actually just inverting a ‘System.GetField(entity)’ in to a more idiomatic single-dispatch style of ‘entity.GetField()’.

      “Statically typed? Yes sir. The individual systems are free to store their components however they want (They don’t even have to use the component type to do it. How about sticking the data in a struct of arrays instead of an array of structs?)”

      Again, there’s nothing precluding this.

      “Thread safety? If two systems don’t care about the same component types, they are inherently thread safe. If they do share the same component type, the need for access control is confined to that specific component.”

      I don’t think there’s any difference here except that the third approach means there’s no threading concern with respect to components being added/removed dynamically (as I alluded to in the advantages/disadvantages list for the first approach).

      “Sorry for shitting on your article. I’m exploring similar territory trying to implement duck typing in C# and I’m running into many of the same issues.”

      Criticism is always welcome :) I wish you luck in your own endeavours too.

      Like

Add a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s