June 20, 2013
The OO implementations that I am used to (C++ and D) do not do virtualization at the data level. Only member functions are virtual.

One of the reasons is that virtual functions remove the need to know what the exact derived type is. The compiler jumps off the virtual function pointer table and the actual virtual member function for the object gets called.

There are rare cases where the actual derived type may be useful. In such cases a series of casts are applied as Steven has shown.

On 06/19/2013 08:35 PM, Stephen Jones wrote:

> Wouldn't it be easier to simply write bars[1].derived.val and let the
> compiler look to and accept val if it is declared in the derived class,
> else gracefully accept val if it is only declared in the base class?

I don't think that implementation has any chance. A statically typed language like D will not do that kind of search at runtime. The code gets compiled by static types of variables. That's all. If it's a Base, it's a Base.

Ali

June 20, 2013
On Wed, 19 Jun 2013 19:10:39 -0400, Stephen Jones <siwenjo@gmail.com> wrote:

>> Hm... would be a nice idiom to implement generically in D.  Like a type switch.
>>
>> -Steve
>
> That is what I would prefer, but I tried:
>
> writeln(to!(typeof(bars[1]))(bars[1]).val);	
>
> to see if I could access the "DERIVED" (thanks) class type but even though bars[1] is initialized as a new Foos its type is still marked as Bar. So the question is, how do you find the derived class type when presented with only the super class?

You have to understand, D is statically typed.  There are two types involved here, the dynamic, object-oriented type, which is only known at runtime, and the static type which is known by the compiler.

typeof(bars[1]) gets the *static* type, or the type that the compiler knows.  bars is a Bar[], so the compiler only knows that bars[1] is a Bar.

The dynamic type of bars[1], as we know, is Foos.  And bars[1] knows it too, but in order to call a function on a derived type, the *compiler* has to know it.  So when you say something like:

if(auto der = cast(Foos)bars[1])

You are telling the compiler:

"OK, I know this is a Bar right now, but check during runtime to see if this is actually a Foos.  If it is, branch in here with 'der' as a variable which is statically typed as Foos."

Then the compiler can know inside that branch, that it can access bars[1] via the static type Foos, and you have access to all Foos' members.  Note that if the instance is actually a derivative of Foos, the compiler STILL will go into that branch!

The "correct" way to do this is to define what you are looking for as a virtual or abstract method on the base class/interface, and then the compiler does all this work for you (but it's only a vtable lookup, so it's much faster).

But if you DON'T know that all derivatives will support 'val' (and you have to know this when the base class is written), then you have to do this casting dance.

Dynamically typed languages make this easier, but it comes at a price.  Statically typed languages have the compiler check so much more at compile time, so it's much more difficult to make a mistake.  I deal with this all the time on PHP, where you can simply type a variable name wrong, and the compiler (and sometimes during runtime) won't complain, it just thinks you are declaring a new variable on an object instance.

Note that Ali's suggestion of typeid does NOT give you a static type of the most derived type, it's a runtime type information object that has limited capability.  It's like reflection in Java or .Net.  But much less powerful, since D's TypeInfo does not provide a full mapping of members that is able to call methods and whatnot.

So while typeid can tell you what the type is (good for comparing, etc), you can't call methods on it (well, there are a couple, like comparing two objects, but not arbitrary ones).

-Steve
1 2
Next ›   Last »