Parameterized inheritence issues, bug or ignorance?
Joerg Joergonson via Digitalmars-d
digitalmars-d at puremagic.com
Sun Jun 19 17:01:58 PDT 2016
I have a gui based on the following classes:
public class Widget { Widget Parent; }
public class Item : Widget;
public class Button(T : ButtonItem) : Widget { T[] Items; ... }
public class ButtonItem : Item
{
void Do() { auto parent = (cast(Button!ButtonItem)this.Parent);
...}
...
}
All this works great! My gui works, all the buttons work, etc.
I now want to add a new gui widget called a Slider:
public class Slider(T : SliderItem) : Button!T { }
public class SliderItem : ButtonItem { }
Makes sense, right? Slider is derived from Button, and SliderItem
is derived from ButtonItem. `Cause a Slider type is a derivation
of a Button type it would seem we should logically derive all the
parameters too. I wouldn't want a Slider using ButtonItem's...
Seems a bit limiting as my slider's items have to behave like
ButtonItems.
Ok, But doing this, my code crashes for sliders. It does so on
the cast. This is because SliderItem calls ButtonItem's Do since
it wasn't overridden and so this.Parent is of type
Slider!SliderItem.
If I copy Do() to SliderButton and change the cast to
cast(Slider!SliderItem) it works!
That problem is that cast(Button!ButtonItem) returns null when
this.Parent is of type Slider!SliderItem.
My contention is that the cast should pass because both Slider
and SliderItem are derived from Button and Button Item
respectively.
If we think of down casting as "If B is derived from A then
cast(A)B" is valid, it would seem this should hold for
parameterized types.
It seems logical to me that Slider!SliderItem is completely
derived from Button!ButtonItem. Just because it is parameterized
doesn't change that.
In fact, testing shows that the problem isn't the cast on the
class type but on the parameter type.
cast(Button!SliderItem)aSliderObject
works.
If we try to then cast that to ButtonItem, if fails:
cast(Button!ButtonItem)[cast(Button!SliderItem)aSliderObject]
The [...] passes and we end up with a Button!SliderItem type the
our SliderItem's types are down cast to ButtonItems. Both should
be valid!
We can take a SliderItem x; and down cast x to a ButtonType so
why can't we do it for a whole crap load of SliderItem objects
that the class my use? Just because it is a parameter shouldn't
change that.
(BTW, I agree that it shouldn't work if SliderItem is not derived
from ButtonItem. Please don't confuse that problem with this
problem. SliderItem is derived from ButtonItem and that changes
everything... just like it would if we had
cast(ButtonItem)aSliderItem)
So, Am I right in that this should work?
Here is a simpler example
import std.stdio;
class a { }
class b : a { }
class A(T : a)
{
T x;
}
void main(string[] argv)
{
auto y = new A!a();
auto z = new A!b();
y.x = new a();
z.x = new b();
auto p1 = cast(A!a)y;
auto p2 = cast(A!b)z;
auto p3 = cast(A!a)z; // Fail! Why? z.x is of type b which can
be down cast to type a without a problem ->
auto p4 = cast(a)z.x;
}
The last line works, and effectively is the same as the p3. (we
just cast the class type vs field type... but both ultimately go
to the same type. e.g., p3.x = p4)
More information about the Digitalmars-d
mailing list