D casting broke?

ag0aep6g via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Mon Jun 20 16:10:14 PDT 2016


On 06/20/2016 11:33 PM, Joerg Joergonson wrote:
> On Monday, 20 June 2016 at 10:38:12 UTC, ag0aep6g wrote:
[...]
>> Is your position that Button!SliderItem should derive/inherit from
>> Button!ButtonItem, enabling the cast, or do you suppose the cast
>> should succeed because the fields are compatible?
>>
>> I.e., should this work?
>>
>>     class A {int x;}
>>     class B {int x;}
>>     A a;
>>     B b = cast(B) a;
>>
>
> No, not at all. first, A and B are not related, so casting makes no
> sense unless there is a conversion(opCast) or whatever, but that is done
> by the user.
>
> This is exactly opposite of what I am talking about.

Ok, so you suppose there should be a inheritance implied when there's an 
inheritance relation between template arguments. I.e., A!a should be a 
superclass of A!b when a is a superclass of b.

It's worth noting that C++, C#, and Java don't work that way either.

I suspect that there would be major hurdles to overcome to make class 
templates work like that. And even if it can be made to work, it would 
be a surprising special case.

At the core, templates are a simple concept: on instantiation, just 
replace the parameter with the argument. Adding some automatic 
inheritance would make things complicated.

[...]
> The real issue is that Slider!SliderItem doesn't override a method that
> is called when a Slider!SliderItem object is used. The method, in
> Button!ButtonItem casts a Widget to Button!ButtonItem just fine because
> inside Button!ButtonItem, the Widget is of type Button!ButtonItem.
>
> When we are inside a Slider!SliderItem though, the same code is executed
> with the same cast(using Button!ButtonItem) and this fails because if it
> succedded we could potentially store ButtonItems as SliderItems(being an
> "downcast", or similar to the example you gave).
>
> This is the code that has the problem.
>
> It is used inside ButtonItem
>
> auto parent = (cast(cButton!cButtonItem)this.Parent);
>
> and not overridden in SliderItem, but still executed in there at some
> point.
>
> this.Parent is a Slider!SliderItem and I need the cast to work so I can
> access the Item array.
>
> But in Slider the array is of type SliderItem, not ButtonItem as I
> initially thought, because I particularized it.
>
> Hence there is a "hidden" downcast going on. Now, in my case, it doesn't
> matter because I never store items in the wrong type. The code is
> automatically generated and creates the correct type for the correct
> storage class. I realize now though that it is possible that it can be
> done(If I just appended a ButtonItem to the array in ButtonItem, then
> when SliderItem is called, then "non-overridden" method will store a
> ButtonItem in the SliderItem array.

This whole Button/Slider/ButtonItem/SliderItem/etc setup may be too 
complex for me.

This is what I understand you have right now, basically:

     class ButtonItem {}
     class SliderItem : ButtonItem {}
     class Widget {}
     class Button(T : ButtonItem) : Widget { T[] items; }
     class Slider(T : SliderItem) : Button!T {}

And I guess the point of having Button templated is so that Slider gets 
a `SliderItem[] items`, which is more restricted and nicer to use than a 
`ButtonItem[] items` would be.

Maybe un-templatizing Button and Slider is worth exploring. I.e.:

     class Button : Widget { ButtonItem[] items; }
     class Slider : Button {}

Button itself probably doesn't need the most derived type, and can work 
with  with just ButtonItem, right? Of course, Slider would have to make 
sure that only SliderItems find their way into items, and it would need 
to cast accordingly when it wants to use an item as a SliderItem.

Just a thought. Seems simpler than the template stuff, but you may have 
other reasons for the templates which I didn't catch.

[...]
> e.g., List<string> and List<Mystring> may be problemmatic, I should
> still be able to cast List<Mystring> to List<string> and use elements,
> but not store them.
>
> so something like
>
> cast(out Button!ButtonItem)sliderSliderItem; could work, the out being
> obvious that sliderSliderItem is never used to store ButtonItems.
>
> In any case, D can't do this easily it seems so it's all moot.  I just
> copied and pasted the code and changed the cast. It lets me get on with
> life.

As I mentioned in an earlier post, you can cast between unrelated class 
types by casting to void* first: `cast(Foo) cast(void*) bar`. It's 
highly unsafe, of course. Maybe it's even relying on undefined behavior, 
because there is no guarantee that the class layout is compatible.

Regarding the list example, it's of course better to cast individual 
items when using them.


More information about the Digitalmars-d-learn mailing list