On Monday, 20 June 2016 at 23:10:14 UTC, ag0aep6g wrote:
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.


Well, Now I don't think this is possible in all circumstances but I really fail to see how it is any different than any normal cast(the examples give using arrays and storing junk in them). If one is consistent, then I think it is valid and works... but it might require the type system to be too restrictive to be of much use.

But yes, the last line was what I have been stating. I don't think treating A!a and A!b as completely different when a is related to b.

Lets suppose A -> B means B is derived from A. That is, any object of B can be cast to A because the memory layout of A is contained in B and any object of B can be accessed as if it were an A.

Template parameters also can have this property since they are types.

Hence

We have two scenarios:

class A(T);
class a;
class b;
A!a -> A!b // false, because, while both sides contain an A, and there is overlap(this is a partial relationships for everything that is identical in both types... that is, all the stuff that doesn't depend on a and b).


AND

class A(T);
class a;
class b : a;

A!a -> A!b // ? This seems like an obvious logical consequence of inheritance and the ->.

This is the way I am thinking about it.

in A!b, everything that depends on b also depends on a because b is basically `more than` a.

So, if we cast A!b down to A!a, and IF A!b never uses the "extra" part of b that makes it different than a, then the cast should pass.

That is, if all b's in A!b could be cast to a and the code work, then A!b should be cast-able to A!a.

Obviously if A!b uses b objects in a way that can be treated like a's then casting will break if we use a's. (but only if we use a's when b's are expected).

The problem is more complex than just a one time fits all rule which the D type system uses.

A simple example is basically my problem:

class A(T);
class a { stuff using a...}
class b : a { }

In this case, down casting works because b doesn't do anything different than a. Effective b is exactly an a so there is no possible way to have any problems.

So, cast(A!a)A!b should pass. Surely the compiler can be smart enough to figure this out? It's as if b is just an alias for a.

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.

Yes. And it makes sense to do that, right? Because, while, we could use a ButtonItem for Sliders, we would expect since a ButtonItem goes with Buttons that SliderItems should go with Sliders?

E.g., our SliderItems might need to have somewhat different behavior than ButtonItems... the thing that makes them "go with the slider".

Sure, we can include that info in slider but we shouldn't have to.

For example. In my code I have a Moved value for SliderItems. This tells you have far they have moved(been "slid"). Button Items should have this cause they can't move. The Slider type doesn't really care about how much they have been slid. But it fits nicely in SliderItem.

When I downcast to cast(Button!ButtonItem)Slider, I never use anything from Slider/SliderItem because I'm dealing with the Button!ButtonItem portion of Slider(the things that makes it a Button).

Of course, I could, in that part of the code, end up adding a ButtonItem to Slider and that wouldn't be logical. That just never happens in my code because of the design. Items are statically added to the classes they are part of and items are never added or removed... Since it's a gui there is no need for dynamic creation(at least in my apps). I even if I want to do some dynamic creation, it's not a huge deal because I'll just use a Factory to create the objects properly.




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.

The only difference is I would have to do a cast every time I use a SliderItem in Slider. That is kinda what I was trying to avoid.

That was the point of inheriting from ButtonItem and letting the compiler know that SliderItem is ButtonItem. I mistakenly thought that it would understand there is a separation between the two types(there are only two types Button!ButtonItem and Slider!SliderItem... not Button!SliderItem or Button!X or Slider!ButtonItem or whatever).

Remember, all this is because parent is a widget and I need. If I could do something like cast(this)(this.Parent) it would be great and always valid in the code I would create. (because if this = ButtonItem then this.Parent is always a Button. Similarly for Slider/SliderItem).

That is, I never actually do anything like casting a Button!SliderItem down to Button!ButtonItem.

The cast is always on `both sides`, so to speak. Maybe that is the fundamental difference. (I never break the cast up in to two parts like

cast(Button!ButtonItem)cast(Button!SliderItem)slider.

It's always done together because it doesn't make sense to do them partially.

Diagrammatically:

Give,
   Button -> Slider
   ButtonItem -> SliderItem

Then

   Button!ButtonItem -> Slider!SliderItem

Not

   Button!ButtonItem -> Button!SliderItem -> Slider!SliderItem

I don't know if there is a difference, I imagine knowing that the casting always occurs together means something. The intermediate case, which is the problem, never occurs, so to speak.

Of course, I have no way informed the compiler of that... and it wouldn't understand it if I did. Button!SliderItem just makes no sense in my design, and if the compiler could understand that, then surely it could reason a little better about things?


Anyways, it's all kinda moot. I already copied and pasted the code.





Reply via email to