Virtual Inheritance should be default

Pages: 123

Why isn't the iostream example "good"? It shows the benefits of code reuse from two classes, fully functional on their own.


Because it doesn't reuse any code at all. It extracts only a common interface. Anyway, usufulness of a stream interface without knowing if it is an output or input stream is very limited. Never saw a code using the stream base class anywhere.


So to keep code bloat under control, we escalate the number of classes that manage the solution and create new delegate methods that could eventually find their way into user-code?


What bloat? In both solutions you need a class with implementation of Breeding and Taming (which a clever JVM can inline into the parent object, which would be equivalent to C++ multiple inheritance). And proxy methods don't bloat the object size. The only thing is that source code might get slightly longer, but you don't have to pay for it - it can be autogenerated.

But on the other hand, the coupling is not that tight as when using inheritance. Deep and complex inheritance hierarchies are very hard to maintain, even single-inheritance only. Inheritance is a stronger relationship than composition. I'd use a single class for the Mob that has a list of cababilities. That would be much more extensible.


It seems that this way of thinking is moving away from an "is a" relationship to an "is capable of doing" relationship. Maybe we should rename object oriented programming to behavior oriented programming to match


Inheritance and polymorphism is not a mandatory feature at all in OOP, do you know it?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Mob: public virtual Entity
{
    double x, y, z;
public:
    Mob(double x, double y, double z) : x(x), y(y), z(z) {}
    virtual void Draw(/**/) const {/*drawing implementation*/}
    virtual /*texture*/ Texture() const = 0;
    virtual void Tick() = 0;
    virtual ~Mob(){}
};

class Breedable: public virtual Mob
{
    bool gender;
public:
    Breedable(bool gender) : gender(gender) {}
    virtual void Tick(){/*breeding implementation*/}
    virtual ~Breedable(){}
};
class Tameable: public virtual Mob
{
    std::string owner;
public:
    Tameable(const std::string &owner) : owner(owner)
    virtual void Tick(){/*taming implementation*/}
    virtual ~Tameable(){}
};

class Ocelot: public virtual Tameable, public virtual Breedable
{
    std::vector</*image*/>::size_t textureID;
public:
    Ocelot() : textureID(rand()%3) {}
    virtual void Tick()
    {
        Breedable::Tick();
        Tameable::Tick();
        //Ocelot implementation
    }
    virtual /*texture*/ Texture(){ return /*textures*/[textureID]; }
    virtual ~Ocelot(){}
};
This is a nice-looking implementation in C++. I want to see, because I am honestly interested, better solutions. Any language will do, especially Java :)
closed account (o1vk4iN6)
rapidcoder wrote:
The only thing is that source code might get slightly longer, but you don't have to pay for it - it can be autogenerated.


C++ has reflection that is on par if not better than Java's - it just has to be auto generated :).
Nope. Compiled libraries don't leave any information for autogeneration tools :p
rapidcoder wrote:
What bloat? In both solutions you need a class with implementation of Breeding and Taming (which a clever JVM can inline into the parent object, which would be equivalent to C++ multiple inheritance).


The point I was stressing is that when using a proxy class, user code will still need to explicitly invoke the proxy. Even if it's auto-generated, it's sloppy and adds complexity to libraries that are designed to be extensible. The generated byte-code and how clever a virtual machine is won't fix the problem of nicely asking the users to invoke this proxy here and there without being able to enforce it at compile-time.
Last edited on

user code will still need to explicitly invoke the proxy


No, usercode calls the class in the same way as it was using multiple inheritance.
The only difference is in the implementation of the class inheriting many behaviours.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public interface MobBehaviour {
     void tick(); 
}

public abstract class Mob {
  protected double x;
  protected double y;
  protected double z;
  
  protected List<MobBehaviour> behaviours = Lists.newArrayList();
   
  public Mob(double x, double y, double z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }  
  
  public void tick() {
     for (MobBehaviour mb : behaviours)
        mb.tick();
  }
  
  public void draw() {  ... }  // drawing implementation
}

public class Breedable implements MobBehaviour {
   // private data here
   void tick() { ... }  
}

public class Tameable implements MobBehaviour {
   // private data here
   void tick() { ... }
}

public class Ocelot extends Mob {
   public Ocelot(double x, double y, double z) {
      super(x, y, z);
      this.behaviours = Lists.newArrayList(new Breedable(), new Tameable());
   } 
}



The composition approach is also much more flexible - I have more control over how behaviours are composed (e.g. I can prioritize them). And additionally I can add behaviours dynamically, implementing roles. You don't get that control andf flexibility with inheritance, and the code using inheritance is also not much shorter.


Last edited on
I'm beat. That's pretty cool :)
closed account (S6k9GNh0)
D also does this. I preferably haven't used multiple inheritance since I first started using C++ nor do I think I ever will again. But To say one way is better than the other isn't really my place I think.

Someone might eventually revive the idea of multiple inheritance but even if they don't, it's still taught as a de facto in classes (college courses).
Last edited on
Next, we need a way for an overrideable method to declare that overriding methods must, at some point in the overridden method, call the method being overridden.

And @rapidcoder's example: there's no public relationship between Ocelot and Breedable or Tameable. Sorry, I just had to complain - I know how to fix it.
Last edited on
D doesn't have class MI. It has mixins, though, so similar approach to Scala or JS. Mixins are something inbetween interface MI (Java) and full MI (C++). Mixins allow for inheriting behaviour, but without problems with construction / destruction.
Storing behaviors in a list has its weaknesses. With multiple inheritance a behavior can add a data member which deriving behaviors can modify.

For example, you might have a MagicMob which stores remaining MP and any other information needed to cast spells. If more concrete behaviors like AI systems need to be able to cast spells, they can derive from MagicMob. This works even if a particular Mob needs to have multiple behaviors related to magic.

If you go with the list design, two behaviors cannot share the same MP value. As a result, you have to implement every possible combination of magic-related behaviors that will ever be used, and the number of combinations quickly explodes out of control.
You could simply update the MP after the magic is done. By instance passing you as a parameter to the behaviour.
But then all Mobs need to have an MP field, even those for which magic would be completely ridiculous. Putting all possible data members in the class doesn't scale nicely, especially if they are large.
closed account (S6k9GNh0)
For the sake of discussion, what does MI and MP stand for specifically?
MI: multiple inheritance
MP: manna magic points

> But then all Mobs need to have an MP field,
No
1) templates
a) return the cost.
\alpha) pass around the `object' MP (created dynamically, you don't need MP, if you sell all your spells)
Last edited on
You don't need an mp field if you don't ask questions.

Either way, I wouldn't use inheritance in such a way anyways. If you have mobs that have MP and some that don't, and you use inheritance to implement the difference, how are you going to leverage that? Are you going to ask each Mob if it's a Magic mob so you know it's ok to ask it for it's MP? Or are you gonna store Mobs and MagicMobs separately? Either way would souind rather crazy to me. Another option would be to let the mobs decide what's it gonna be - which gets us back to encapsulating behavior.
Personally, I wouldn't even be considering any of this or that yet - MagicMob doesn't even sound like it is past the "generate ideas" stage yet. How will magic mobs behave and interact? What will they have in common? What will they not?
Last edited on
closed account (S6k9GNh0)
I was saying D did NOT use multiple inheritance and was relating to the example provided that didn't use multiple inheritance.

However, an interface can inherit from multiple interfaces, just not the implementation of that interface, i.e. every new interface must be re-implemented.

http://dlang.org/interface.html
1) templates


Well, then you can't put the two kinds of Mobs in the same container. That is, unless one inherits from the other, but then you'll run into MI again if you have more than one strange kind of Mob and one concrete Mob needs both of the characteristics.

a) return the cost.


Return it to where? In OOP you would expect the (concrete) Mob class to contain all the fields necessary to track an instance of that Mob. You don't want one random field to be outside the class.

If you have mobs that have MP and some that don't, and you use inheritance to implement the difference, how are you going to leverage that? Are you going to ask each Mob if it's a Magic mob so you know it's ok to ask it for it's MP? Or are you gonna store Mobs and MagicMobs separately?


Each kind of Mob (abstract or concrete) that needs to use MP simply inherits from MagicMob. Those behaviors are guaranteed to have access to the MP field which is guaranteed to exist. Because MagicMob extends Mob, you can store all the Mobs in a single container. This also extends to situations where there are even more kinds of Mobs with new data members (and you can mix and match properly).

MagicMob doesn't even sound like it is past the "generate ideas" stage yet. How will magic mobs behave and interact? What will they have in common? What will they not?


A MagicMob is a very general extension of Mob: one that needs to keep track of MP.
Last edited on
hanst99 wrote:
If you have mobs that have MP and some that don't, and you use inheritance to implement the difference, how are you going to leverage that? Are you going to ask each Mob if it's a Magic mob so you know it's ok to ask it for it's MP? Or are you gonna store Mobs and MagicMobs separately?
This is actually a terrible argument, because in OOP you never need to know the type of an object. I've used this argument before and been told off many times, even by you once I believe.
Pages: 123