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.

Reply via email to