Re: D casting broke?

2016-06-21 Thread Joerg Joergonson via Digitalmars-d-learn

On Tuesday, 21 June 2016 at 02:39:25 UTC, H. S. Teoh wrote:
On Tue, Jun 21, 2016 at 02:09:50AM +, Joerg Joergonson via 
Digitalmars-d-learn wrote: [...]
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.


Correct.


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

[...]

The template *parameters* can also have this property. But the 
*template* itself may not.  Contrived example:


class A { int x; }
class B : A { int y; }

struct Templ(C : class) {
int[C.sizeof] data;
}

Templ!A a;
Templ!B b;

a = b; // should this be allowed?

It should be clear that allowing this would cause problems, 
because in spite of the relationship between A and B, and hence 
the relationship between the template arguments of a and b, the 
same relationship does not hold between Templ!A and Templ!B 
(note that .data is an array of ints, not ubytes, and may not 
contain data in any layout that has any corresponds with the 
relationship between A and B).


Another contrived example:

class A { int x; }
class B : A { int y; }

struct Templ(C : class) {
static if (C.sizeof > 4) {
string x;
} else {
float y;
}
}

Allowing implicit casting from Templ!B to Templ!A would not 
make sense, because even though the respective template 
arguments have an inheritance relationship, the Templ 
instantiation made from these classes has a completely 
unrelated and incompatible implementation.




Well, I never mentioned any implicit casting. Obviously explicit 
casting wouldn't make sense either. It is a good example as it 
can show that Templ!A is completely different than Templ!B and no 
conversion is every possible even if A and B are related.


But I still think these are different examples.

You are talking about A!a vs A!b while I am talking about A!a vs 
B!b. I believe, but could be mistaken, that there is a subtle 
difference. I know it seems like B!b can be reduced to A!b, and 
the type system allows this... but if it never happens then all 
these cases explaining the problem of going from A!b to A!a are 
moot.


Now granted, these are contrived examples, and in real-life we 
may not have any real application that requires such strange 
code. However, the language itself allows such constructs, and 
therefore the compiler cannot blindly assume any relationship 
between Templ!A and Templ!B even though there is a clear 
relationship between A and B themselves.


I agree. I am not asking for blind assumptions. When I inform the 
compiler I want to cast to an object that I know should 
succeed(it was designed to do so) I don't expect a null. (As has 
been mentioned, I can do this using the void* trick, so there is 
a way)


What should be done if we wish to allow converting Templ!B to 
Templ!A, though?  One way (though this still does not allow 
implicit casting) is to use opCast:


struct Templ(C : class) {
... // implementation here

auto opCast(D : class)
if (is(C : D)) // C must be a base class of D
{
...
// do something here to make the conversion
// valid. Maybe something as simple as:
return cast(Templ!D) this;

// (provided that there are no memory layout
// problems in Templ's implementation, of
// course).
}
}

Implementing this using opCast actually gives us an even more 
powerful tool: provided it is actually possible to convert 
between potentially incompatible binary layouts of Templ!A and 
Templ!B, the opCast method can be written in such a way as to 
construct Templ!A from Templ!B in a consistent way, e.g., by 
treating B as a subclass of A and calling the ctor of Templ!A, 
or, in the case of my contrived examples, do something 
non-trivial with the .data member so that the returned Templ!A 
makes sense for whatever purpose it's designed for.  It allows 
the implementor of the template to specify exactly how to 
convert between the two types when the compiler can't possibly 
divine this on its own.




While this is nice, the problem was how to convert. Even in 
opCast I would get a null and I wouldn't want to reconstruct A!a 
from B!b because that would essentially entail duplication. Of 
course, now I know I can just cast to void* then back and 
essentially trick/bypass the compilers type system checking.


This is kind of bringing a nuclear warhead to an anthill, 
though.  In my own code where I have a template wrapping around 
types that need to convert to a common base type, I find it 

Re: D casting broke?

2016-06-21 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/20/16 10:45 PM, Joerg Joergonson wrote:

On Monday, 20 June 2016 at 23:35:28 UTC, Steven Schveighoffer wrote:

On 6/19/16 5:19 PM, Joerg Joergonson wrote:

On Sunday, 19 June 2016 at 20:21:35 UTC, ag0aep6g wrote:

On 06/19/2016 09:59 PM, Joerg Joergonson wrote:

This should be completely valid since B!T' obviously derives from A!T
directly


ok


and we see that T' derives from b which derives from a
directly.


ok


So B!b is an entirely derived from A!a


No. B!b is derived from A!b, not from A!a. `b` being derived from `a`
does not make A!b derived from A!a.


why not? This doesn't seem logical!


Because:

class A(T : a)
{
  static if(is(T == a))
 int oops;
  ...
}

Now A!b and A!a have different layouts. They cannot be related, even
if the template arguments are related. I could introduce another
virtual function inside the static if, same result -- vtable is messed
up.

In general, an instantiation of a template aggregate (class or struct)
is not castable implicitly to another instantiation of the same
aggregate unless explicitly declared.

And note that D does not allow multiple inheritance. I don't think you
can solve this problem in D.



Yes, but all you guys are doing is leaving out what I'm actually doing
and creating a different problem that may not have the same issues.


We're not "creating" any different problems. The compiler has to assume 
the worst, especially when it must make assumptions at runtime. The same 
template instantiated with different parameters is different, not 
related. In order for it to be related, you have to declare that somehow.


-Steve


Re: D casting broke?

2016-06-20 Thread Joerg Joergonson via Digitalmars-d-learn
On Monday, 20 June 2016 at 23:35:28 UTC, Steven Schveighoffer 
wrote:

On 6/19/16 5:19 PM, Joerg Joergonson wrote:

On Sunday, 19 June 2016 at 20:21:35 UTC, ag0aep6g wrote:

On 06/19/2016 09:59 PM, Joerg Joergonson wrote:
This should be completely valid since B!T' obviously derives 
from A!T

directly


ok


and we see that T' derives from b which derives from a
directly.


ok


So B!b is an entirely derived from A!a


No. B!b is derived from A!b, not from A!a. `b` being derived 
from `a`

does not make A!b derived from A!a.


why not? This doesn't seem logical!


Because:

class A(T : a)
{
  static if(is(T == a))
 int oops;
  ...
}

Now A!b and A!a have different layouts. They cannot be related, 
even if the template arguments are related. I could introduce 
another virtual function inside the static if, same result -- 
vtable is messed up.


In general, an instantiation of a template aggregate (class or 
struct) is not castable implicitly to another instantiation of 
the same aggregate unless explicitly declared.


And note that D does not allow multiple inheritance. I don't 
think you can solve this problem in D.


-Steve


Yes, but all you guys are doing is leaving out what I'm actually 
doing and creating a different problem that may not have the same 
issues.


I have this:

(Button!ButtonItem) : (Slider!SliderItem)


In my code/design that is different than

Button!ButtonItem : Button!SliderItem : Slider!SliderItem

The middle case, the case you guys are reducing do, never occurs. 
I never have that problem because I never *mix* a Button with a 
SliderItem. It makes no sense in my design. Hence I don't have to 
worry about that case, but that is the case you guys keep 
bringing up.


A SliderItem adds info to a ButtonItem that makes it "slider 
like". In my case, A slide amount. This field is useless to use 
in a Button. It is only used by the Slider class(In fact, only by 
SliderItem).


I realize that if one did a cast of a Button!SliderItem down to a 
Button!ButtonItem, things can become problematic. This doesn't 
occur in my design.


I see it more like


[Button!ButtonItem]
   |
   v
[Slider!SliderItem]


rather than


Button!ButtonItem
   |
   v
Button!SliderItem
   |
   v
Slider!SliderItem


or

Button!ButtonItem
   |
   v
Slider!ButtonItem
   |
   v
Slider!SliderItem


The first has the problem casting Button!SliderItem to 
Button!ButtonItem. (Same as List!mystring to List!string)


The second has the problem Slider!SliderItem to Slider!ButtonItem 
(It's the same problem in both)



There seems to be three relationships going on and D does one.

Let != not related(not derived from)
For a and b

a != b. D's assumption, never safe
a -> b works some of the time depending on usage
a = b works all the time

But it is more complex with A!a and B!b

A != B and a != b. never safe to cast in any combination
A != B and a = b. never safe to cast
A != B and a -> b. never safe to cast
A -> B and a != b. never safe to cast
A = B and a != b. never safe to cast
A -> B and a -> b. Sometimes safe to cast
A -> B and a = b. Sometimes safe to cast
A = B and a = b. Always safe to cast

Things get "safer" to cast as the relationships between the types 
becomes more "exact".  D always assumes worst case for the 
template parameters.


Some designs, though, work in the A -> B and a -> b 'region' with 
the fact that A!b never occurs, which as been shown is 
problematic through out this thread(but it is really just an 
extension of the first case because both are derivation from A 
and it really adds nothing to the complexity).

































Re: D casting broke?

2016-06-20 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jun 21, 2016 at 02:09:50AM +, Joerg Joergonson via 
Digitalmars-d-learn wrote:
[...]
> 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.

Correct.


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

The template *parameters* can also have this property. But the
*template* itself may not.  Contrived example:

class A { int x; }
class B : A { int y; }

struct Templ(C : class) {
int[C.sizeof] data;
}

Templ!A a;
Templ!B b;

a = b; // should this be allowed?

It should be clear that allowing this would cause problems, because in
spite of the relationship between A and B, and hence the relationship
between the template arguments of a and b, the same relationship does
not hold between Templ!A and Templ!B (note that .data is an array of
ints, not ubytes, and may not contain data in any layout that has any
corresponds with the relationship between A and B).

Another contrived example:

class A { int x; }
class B : A { int y; }

struct Templ(C : class) {
static if (C.sizeof > 4) {
string x;
} else {
float y;
}
}

Allowing implicit casting from Templ!B to Templ!A would not make sense,
because even though the respective template arguments have an
inheritance relationship, the Templ instantiation made from these
classes has a completely unrelated and incompatible implementation.

Now granted, these are contrived examples, and in real-life we may not
have any real application that requires such strange code. However, the
language itself allows such constructs, and therefore the compiler
cannot blindly assume any relationship between Templ!A and Templ!B even
though there is a clear relationship between A and B themselves.

What should be done if we wish to allow converting Templ!B to Templ!A,
though?  One way (though this still does not allow implicit casting) is
to use opCast:

struct Templ(C : class) {
... // implementation here

auto opCast(D : class)
if (is(C : D)) // C must be a base class of D
{
...
// do something here to make the conversion
// valid. Maybe something as simple as:
return cast(Templ!D) this;

// (provided that there are no memory layout
// problems in Templ's implementation, of
// course).
}
}

Implementing this using opCast actually gives us an even more powerful
tool: provided it is actually possible to convert between potentially
incompatible binary layouts of Templ!A and Templ!B, the opCast method
can be written in such a way as to construct Templ!A from Templ!B in a
consistent way, e.g., by treating B as a subclass of A and calling the
ctor of Templ!A, or, in the case of my contrived examples, do something
non-trivial with the .data member so that the returned Templ!A makes
sense for whatever purpose it's designed for.  It allows the implementor
of the template to specify exactly how to convert between the two types
when the compiler can't possibly divine this on its own.

This is kind of bringing a nuclear warhead to an anthill, though.  In my
own code where I have a template wrapping around types that need to
convert to a common base type, I find it more useful to use the
following pattern instead:

class A { ... }
class B : A { ... }

class WrapperBase {
... // common stuff for all instantiations of Wrapper!X
}

class Wrapper(C : class) : WrapperBase {
... // stuff specific to C
}

Wrapper!A a;
Wrapper!B b;
WrapperBase wb = a; // OK
wb = b; // also OK

This may or may not be what you're looking for, though.


T

-- 
It said to install Windows 2000 or better, so I installed Linux instead.


Re: D casting broke?

2016-06-20 Thread Joerg Joergonson via Digitalmars-d-learn

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 

Re: D casting broke?

2016-06-20 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/19/16 5:19 PM, Joerg Joergonson wrote:

On Sunday, 19 June 2016 at 20:21:35 UTC, ag0aep6g wrote:

On 06/19/2016 09:59 PM, Joerg Joergonson wrote:

This should be completely valid since B!T' obviously derives from A!T
directly


ok


and we see that T' derives from b which derives from a
directly.


ok


So B!b is an entirely derived from A!a


No. B!b is derived from A!b, not from A!a. `b` being derived from `a`
does not make A!b derived from A!a.


why not? This doesn't seem logical!


Because:

class A(T : a)
{
  static if(is(T == a))
 int oops;
  ...
}

Now A!b and A!a have different layouts. They cannot be related, even if 
the template arguments are related. I could introduce another virtual 
function inside the static if, same result -- vtable is messed up.


In general, an instantiation of a template aggregate (class or struct) 
is not castable implicitly to another instantiation of the same 
aggregate unless explicitly declared.


And note that D does not allow multiple inheritance. I don't think you 
can solve this problem in D.


-Steve


Re: D casting broke?

2016-06-20 Thread ag0aep6g via Digitalmars-d-learn

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 and List may be problemmatic, I should
still be able to cast List to List 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.


Re: D casting broke?

2016-06-20 Thread Joerg Joergonson via Digitalmars-d-learn

On Monday, 20 June 2016 at 10:38:12 UTC, ag0aep6g wrote:

On 06/20/2016 01:40 AM, Joerg Joergonson wrote:

public class Button(T : ButtonItem) : Widget { ... }
public class ButtonItem : Item
{
  void Do() { auto parent = 
(cast(Button!ButtonItem)this.Parent); }

  ...
}

All this works great! As long as Do is not being called from a 
derived

class

public class Slider(T : SliderItem) : Button!T { }
public class SliderItem : ButtonItem { }


The last two classes are truly empty. Now, when I use a Slider 
object,
things go to shit because the cast is invalid. this.Parent is 
of type

Slider!SliderItem.


It's the same setup as with the A and B things, right?

Parent is a Widget that holds a Slider!SliderItem. That's fine 
because Slider!SliderItem is derived from Button!SliderItem 
which is derived from Widget.


But Button!SliderItem does not derive from Button!ButtonItem. 
They both derive from Widget. So the cast fails.


But you think it should succeed, of course.

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.

SliderItem only sets the array type. So in Slider, I end up 
with a
SliderItem[] type then in ButtonItem's Do(which gets called 
since

SliderItem doesn't override), it tries to cast that down to a
ButtonItem. It should work. There is no reason it shouldn't 
logically.

There is no up casting.


Some terminology clarification: Casting from SliderItem to 
ButtonItem is upcasting. The other direction would be 
downcasting. Upcasting a single object is trivial and can be 
done implicitly. Downcasting must be done explicitly and may 
yield null.


You say that you cast from SliderItem to ButtonItem. But that's 
not what's done in your snippet above. You try to cast from 
Button!SliderItem to Button!ButtonItem. Completely different 
operation.


Ok, I might have used terminology backwards.

The problem is more complex then maybe I demonstrated and anyone 
has mentioned. Yes, there might be an issue with 
downcasting/contravariance and all that. I think those problems 
though, are general issues.


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.



So, this isn't really a problem with casting so much as it is 
with the complexity of the inheritence. By doing it the way I 
did, to try to keep the Types and parameters synced and because 
they inherit from each other, there can be problems.


To get what I want, which is probably impossible, I'd need the 
cast to automatically cast in the correct type depending on where 
it is being executed:


auto parent = (cast(typeof(parent)!this)this.Parent);   

Which, of course, is impossible to do at compile time.

I only need parent to check if it's items exist in the array

if (parent.HoveredItems.canFind(this))


That is all it is used for, so there is no problem with it, but 
if I don't cast I obviously can't access the HoverdItems... but 
then the cast breaks for derived classes and parent is null.


To make it work I'd have to add, say, something like 
containsHovered to Widget. Then I wouldn't need the cast, but 
this doesn't make a lot of sense, since Widget doesn't contain an 
array of HoveredItems.


Alternatively I could add an interface to 

Re: D casting broke?

2016-06-20 Thread ag0aep6g via Digitalmars-d-learn

On 06/20/2016 01:40 AM, Joerg Joergonson wrote:

public class Button(T : ButtonItem) : Widget { ... }
public class ButtonItem : Item
{
  void Do() { auto parent = (cast(Button!ButtonItem)this.Parent); }
  ...
}

All this works great! As long as Do is not being called from a derived
class

public class Slider(T : SliderItem) : Button!T { }
public class SliderItem : ButtonItem { }


The last two classes are truly empty. Now, when I use a Slider object,
things go to shit because the cast is invalid. this.Parent is of type
Slider!SliderItem.


It's the same setup as with the A and B things, right?

Parent is a Widget that holds a Slider!SliderItem. That's fine because 
Slider!SliderItem is derived from Button!SliderItem which is derived 
from Widget.


But Button!SliderItem does not derive from Button!ButtonItem. They both 
derive from Widget. So the cast fails.


But you think it should succeed, of course.

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;


SliderItem only sets the array type. So in Slider, I end up with a
SliderItem[] type then in ButtonItem's Do(which gets called since
SliderItem doesn't override), it tries to cast that down to a
ButtonItem. It should work. There is no reason it shouldn't logically.
There is no up casting.


Some terminology clarification: Casting from SliderItem to ButtonItem is 
upcasting. The other direction would be downcasting. Upcasting a single 
object is trivial and can be done implicitly. Downcasting must be done 
explicitly and may yield null.


You say that you cast from SliderItem to ButtonItem. But that's not 
what's done in your snippet above. You try to cast from 
Button!SliderItem to Button!ButtonItem. Completely different operation.




Re: D casting broke?

2016-06-19 Thread Joerg Joergonson via Digitalmars-d-learn

On Sunday, 19 June 2016 at 23:00:03 UTC, ag0aep6g wrote:

On 06/19/2016 11:19 PM, Joerg Joergonson wrote:

On Sunday, 19 June 2016 at 20:21:35 UTC, ag0aep6g wrote:

[...]
No. B!b is derived from A!b, not from A!a. `b` being derived 
from `a`

does not make A!b derived from A!a.


why not? This doesn't seem logical!


Template parameters simply don't work like that. A template can 
result in completely unrelated types based on template 
parameters.


For example:

template C(T)
{
static if (is(T == A)) class C {}
else static if(is(T == B)) alias C = int;
else struct C {int x;}
}

As you see there can't be any inheritance relation between the 
different instantiations of the C template here. Having such a 
relation for different instantiation that result in classes 
would be a weird special case.


There's probably a really simple and obvious reason why that 
special would be a bad idea in itself, but I'm not able to 
point it out. Maybe make a thread in the General group. I think 
the language people tend to focus their attention there.


Criticism and improvement proposals are also better directed to 
the General group.



Here is the full inheritance tree:

X
├─x
│ └─a
│   └─b
├─A!a
└─A!b
  └─B!b



But b is derived from a.


Yeah, that's right there in the middle.


Your tree completely ignores under A.


Clearly, there's B!b under A!b. That's it. Nothing exists below 
B!b. B!a doesn't exist either. A!a is on a different branch. I 
don't think I've missed anything.


[...]
Just because D doesn't understand this logical consistency 
between
inheritance doesn't mean D is right. (Hence, why D's type 
system is broke)



In fact, the tree should look like this:


X
├─x
│ └─a
│   └─b
└─A!x

 │  \
 └─A!a
   │  \
   └─A!b
 │  \
 └─B!b


I'm having trouble reading this. A!x isn't valid, as the 
constraint on A says `T : a`, but x doesn't satisfy that.




no, my point was that a is derived from x, b from a, hence we 
have a derivation change x -> a -> b. So, similarly A!x -> A!a -> 
A!b


I also don't understand what the backslashes mean. They just 
repeat the other lines, don't they? Or do they connect x, a, 
and b? That's already expressed in the upper section.


Yes, they connect them. Yes, exactly, But this time they connect 
in terms of A. The compiler doesn't seem to use the fact that x 
-> a -> -> b to infer anything about A!x -> A!a -> A!b, and it 
should.




As for A!b being below A!a, I can only repeat that this 
inheritance is not implied. You would have to spell it out 
explicitly for the compiler to pick it up.




Maybe so. But that is kinda my point.


Basically you are treating A!a and A!b as if a and be have no
relationship. BUT THEY DO!


Well, to the compiler they don't.


Yes, exactly.


basically I am doing a cast(A!a)this because all I care about is 
this in terms of A!a. If it's a B!b or B!a or A!b is immaterial 
to me since casting to A!a gets me what I need. (It's no 
different than if I was doing simpler inheritance) D doesn't 
understand this and there is no simple fix that anyone has 
presented.


The casting is the only problem and there is no reason it should 
fail because the object I am casting on can be cast to it's base 
class.


If we assume that I'm wrong or D can't do this because of a bug 
or shortsightedness... the issue remains on how to make it work.


public class Button(T : ButtonItem) : Widget { ... }
public class ButtonItem : Item
{
 void Do() { auto parent = (cast(Button!ButtonItem)this.Parent); }
 ...
}

All this works great! As long as Do is not being called from a 
derived class


public class Slider(T : SliderItem) : Button!T { }
public class SliderItem : ButtonItem { }


The last two classes are truly empty. Now, when I use a Slider 
object, things go to shit because the cast is invalid. 
this.Parent is of type Slider!SliderItem.


SliderItem only sets the array type. So in Slider, I end up with 
a SliderItem[] type then in ButtonItem's Do(which gets called 
since SliderItem doesn't override), it tries to cast that down to 
a ButtonItem. It should work. There is no reason it shouldn't 
logically. There is no up casting.


If I duplicate Do() and put it in SliderItem and change the cast 
to use Slider/SliderItem, it works. The cast is the only problem. 
Not the objects themselves.


If this wasn't a parameterized class, everything would work. If I 
made Slider use ButtonItems everything would work. It's only 
because I derived a new type SldierItem from ButtonItem that 
breaks and only at the cast.



I'm almost 100% sure this should work and haven't seen anyone 
actually show why this would not work(the examples given are 
simply wrong and are not understanding the problem... or there is 
more going than anyone has said).


Again, do we not expect derived types to be able to be down cast? 
Just because they are parameterized on other types doesn't change 
this fact? It just makes it more 

Re: D casting broke?

2016-06-19 Thread ag0aep6g via Digitalmars-d-learn

On 06/19/2016 11:19 PM, Joerg Joergonson wrote:

On Sunday, 19 June 2016 at 20:21:35 UTC, ag0aep6g wrote:

[...]

No. B!b is derived from A!b, not from A!a. `b` being derived from `a`
does not make A!b derived from A!a.


why not? This doesn't seem logical!


Template parameters simply don't work like that. A template can result 
in completely unrelated types based on template parameters.


For example:

template C(T)
{
static if (is(T == A)) class C {}
else static if(is(T == B)) alias C = int;
else struct C {int x;}
}

As you see there can't be any inheritance relation between the different 
instantiations of the C template here. Having such a relation for 
different instantiation that result in classes would be a weird special 
case.


There's probably a really simple and obvious reason why that special 
would be a bad idea in itself, but I'm not able to point it out. Maybe 
make a thread in the General group. I think the language people tend to 
focus their attention there.


Criticism and improvement proposals are also better directed to the 
General group.



Here is the full inheritance tree:

X
├─x
│ └─a
│   └─b
├─A!a
└─A!b
  └─B!b



But b is derived from a.


Yeah, that's right there in the middle.


Your tree completely ignores under A.


Clearly, there's B!b under A!b. That's it. Nothing exists below B!b. B!a 
doesn't exist either. A!a is on a different branch. I don't think I've 
missed anything.


[...]

Just because D doesn't understand this logical consistency between
inheritance doesn't mean D is right. (Hence, why D's type system is broke)


In fact, the tree should look like this:


X
├─x
│ └─a
│   └─b
└─A!x

 │  \
 └─A!a
   │  \
   └─A!b
 │  \
 └─B!b


I'm having trouble reading this. A!x isn't valid, as the constraint on A 
says `T : a`, but x doesn't satisfy that.


I also don't understand what the backslashes mean. They just repeat the 
other lines, don't they? Or do they connect x, a, and b? That's already 
expressed in the upper section.


As for A!b being below A!a, I can only repeat that this inheritance is 
not implied. You would have to spell it out explicitly for the compiler 
to pick it up.



Basically you are treating A!a and A!b as if a and be have no
relationship. BUT THEY DO!


Well, to the compiler they don't.


If you don't take that into account then your
wrong.

Simply stating how D behaves is not proof of why it is right or wrong.


For discussions about how D should behave, please post to General. Here 
in the Learn group I (and I think we) tend to focus on how D works or is 
meant to work. The way you think it should behave here is not how it's 
meant to work by the designers and implementors.


[...]

import std.stdio;
class a { }
class b : a { }

class A(T : a)
{
T x;
}



void main(string[] argv)
{
 auto _A = new A!a();
 auto _C = new A!b();

 auto p = cast(A!a)_C;
}

p is null. My example with B is irrelevant. The issue is with the
parameter.

As you can see, D thinks that A!b and A!a are completely unrelated... as
do you and arsd.

Do you seriously think this is the case? That

class b : a { }

and

class b { }

effectively mean the same with regards to A?


Yes. A!a is a class like this: `class A!a {a x;}`. A!b is this: `class 
A!b {b x;}`. The generated classes have members that have an inheritance 
relationship, but that doesn't imply an inheritance relationship between 
A!a and A!b.



The whole problem comes about at this line:

auto p = cast(A!a)_C;

We are trying to cast `T x` in C, which is effectively `b x` to `a x`.


No. You try to cast from one class type to another, that's different 
from casting the members.


You can have two classes with exactly the same members, yet they're not 
(directly) castable to each other when there's no inheritance relation:


class A {int x;}
class B {int x;}
void main()
{
assert((cast(B) new A) is null); /* holds */
assert((cast(A) new B) is null); /* holds */
}

Maybe this is the crux? I'd expect you to be of the opinion that those 
casts should work.


Of course, you can force an unsafe conversion by casting to void* first:

cast(B) cast(void*) new A

A reinterpret-style cast would also work:

A a = new A;
B b = * cast(B*) 

I suppose a simple cast doesn't do that because it's deemed more useful 
to get null when the inheritance doesn't work out, even when the member 
layout would work out. This way `cast` can be used for downcasts in a 
safe manner.


Because, when there is no inheritance relation, that means there is no 
guarantee that a class can be used in place of another one, even when 
the fields are compatible. Consider A and B having methods with the same 
name that do completely unrelated things. Converting accidentally from 
one to the other would be bad.


Re: D casting broke?

2016-06-19 Thread David Nadlinger via Digitalmars-d-learn

On Sunday, 19 June 2016 at 21:06:43 UTC, Joerg Joergonson wrote:
A!b is derived from A!a if b is derived from a, is it not? If 
not, then I am wrong, if so then D casting has a bug.


You are wrong.

The array example given by Adam is actually a neat illustration 
of precisely your question if you just think of `T[]` as 
`Slice!T`. In other words, `Slice!b` cannot be derived from 
`Slice!a` automatically, since then you could use the `Slice!a` 
interface to push `a` instances into your `Slice!b`.


If that's a bit too far of a mental leap to make, you can 
certainly find a more thorough illustration of the concepts at 
play here by looking up covariance vs. contravariance in 
containers/generics online.


 — David


Re: D casting broke?

2016-06-19 Thread Joerg Joergonson via Digitalmars-d-learn

On Sunday, 19 June 2016 at 20:21:35 UTC, ag0aep6g wrote:

On 06/19/2016 09:59 PM, Joerg Joergonson wrote:
This should be completely valid since B!T' obviously derives 
from A!T

directly


ok


and we see that T' derives from b which derives from a
directly.


ok


So B!b is an entirely derived from A!a


No. B!b is derived from A!b, not from A!a. `b` being derived 
from `a` does not make A!b derived from A!a.


why not? This doesn't seem logical!


Here is the full inheritance tree:

X
├─x
│ └─a
│   └─b
├─A!a
└─A!b
  └─B!b



But b is derived from a. Your tree completely ignores under A.


X
├─x
│ └─a
│   └─b
├─A!a

|  \
└─A!b
  └─B!b

Just because D doesn't understand this logical consistency 
between inheritance doesn't mean D is right. (Hence, why D's type 
system is broke)



In fact, the tree should look like this:


X
├─x
│ └─a
│   └─b
└─A!x

│  \
└─A!a
  │  \
  └─A!b
│  \
└─B!b


Basically you are treating A!a and A!b as if a and be have no 
relationship. BUT THEY DO! If you don't take that into account 
then your wrong.


Simply stating how D behaves is not proof of why it is right or 
wrong.


This is very easy to see, check my other post using a Widget 
Example and you will see that it is a logical extension.


D doesn't check parameter inheritance relationships properly. A!b 
is a derivation of A!a.


import std.stdio;
class a { }
class b : a { }

class A(T : a)
{
   T x;
}



void main(string[] argv)
{
auto _A = new A!a();
auto _C = new A!b();

auto p = cast(A!a)_C;
}

p is null. My example with B is irrelevant. The issue is with the 
parameter.


As you can see, D thinks that A!b and A!a are completely 
unrelated... as do you and arsd.


Do you seriously think this is the case? That

class b : a { }

and

class b { }

effectively mean the same with regards to A?

The whole problem comes about at this line:

auto p = cast(A!a)_C;

We are trying to cast `T x` in C, which is effectively `b x` to 
`a x`.


Is that not possible to do? We do it all the time, right?

That is my point. D doesn't see that it can do this but it can, 
if not, prove me wrong.

















Re: D casting broke?

2016-06-19 Thread Joerg Joergonson via Digitalmars-d-learn

On Sunday, 19 June 2016 at 20:18:14 UTC, Adam D. Ruppe wrote:

On Sunday, 19 June 2016 at 19:59:28 UTC, Joerg Joergonson wrote:
This should be completely valid since B!T' obviously derives 
from A!T directly and we see that T' derives from b which 
derives from a directly. So B!b is an entirely derived from 
A!a and hence the cast should be successful


I don't see how you think that. Here's the parent chain:

B!b -> A!b -> X -> x -> Object

There's no A!a in there, the cast is failing correctly.

Just because `b` is a child of `a` doesn't mean that `A!b` is 
the same as `A!a`. Consider an array:


MyClass[] arr;
arr ~= new MyClass(); // ok cool

Object[] obj_arr = arr; // won't work! because...
obj_arr[0] = new RandomClass(); // this would compile...

// but obj_arr and arr reference the same data, so now:
arr[0] is typed MyClass... but is actually RandomClass! It'd 
crash horribly.




Array is just one example of where converting A!b to A!a is 
problematic. The same principle can apply anywhere, so it won't 
implicitly cast them.




I'm not saying they are the same! They don't have to be the same. 
That is the whole point of inheritance and casting. A!b is 
derived from A!a if b is derived from a, is it not? If not, then 
I am wrong, if so then D casting has a bug.








The obviously question: Is there a simple way around this?


What are you actually trying to do?


Do you really want to know? It's very simple and logical and 
might blow your mind and show you it's more complex than the 
example you have


I have a widget class

class Widget { Widget Parent; }

I have a button item class

class ButtonItem : Widget;

I have a button class

class Button : Widget { ButtonItem[] items; }

Make sense so far? Very logical and all that?

NOW, suppose I want to create a derived type from button? Say, a 
slider that effectively is a button that can move around:


class Slider : Button { }

So far so good, right?

WRONG! Slider shouldn't contain button items but slider items! 
How to get around this?



class SliderItem : ButtonItem; (since sliders are buttons slider 
items should be button items, right?)


So, to make this work we have to parameterize Button.

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


So far so good!

and

class SliderItem : ButtonItem;

Very logical, Spock would be proud!

Now

class Slider(T : SliderItem) : Button!T;


Very logical still, right? Because T is of type SliderItem which 
is of type ButtonItem and therefor Button!SliderItem is of type 
Button!ButtonItem.


Everything works, right? Of course, I have a working example!

Slider!T is a type of Button!T, Slider!SliderItem is a type of 
Button!ButtonItem. Surely items in Button can hold SliderItems? 
(since they are derived from ButtonItems and ButtonItems work)


Ok, everything works!

Now what?

Well, In ButtonItem, I have to get the parent items to do some 
work. i.e.,


Work(Parent.items);

But this can't work because Parent is a Widget, so we must cast 
to a Button.


Work((cast(Button)Parent).items);

But this doesn't work because Button is parameterized. so

Work((cast(Button!T)Parent).items);

But this doesn't work because there is no T in ButtonItem, which 
is were we are at, so lets cast to a ButtonItem.


Work((cast(Button!ButtonItem)Parent).items);

This works!! At least as long as we are in ButtonItems!

When our parent is a Slider then the cast fails and everything 
goes to shit.


I have to duplicate the code AND only change the cast to 
cast(Slider!SliderItem)Parent and then everything works.



But, you might think that Slider!SliderItem is somehow not 
derived from Button!ButtonItem but it is, it was created to be 
that way by god himself.



Widget -> Button -> Slider
 | |
   -> ButtonItem -> SliderItem


First, for one, everything is an Widget, lets get that clear.

Second, Slider!SliderItem is just a wrapper to Button!ButtonItem. 
This allows us to add additional slider based code to a button to 
make it act like a slider(which is more than a button, but still 
a button).



This is just a 2D case of the 1D inheritance Slider is a Button. 
Just because we add a parameterization to it DOESN'T NECESSARILY 
change that. If the parameter also has an inheritance 
relationship then we have a fully valid inheritance relationship.



e.g., Slider!Pocahontas has only a partial inheritance to 
Button!ButtonItem because Pocahontas is not in any way derived 
from ButtonItem. But if Pocahontas is fully derived from 
ButtonItem then the partial inheritance is full inheritance.


Do you understand that?

Else, if you were correct, something like Slider!Widget and 
Button!Widget would never be relatable. Yet it's obvious that it 
is trivially relatable because Widget = Widget. In my case the 
only difference is SliderItem derives from ButtonItem.


We can always cast to a super class. ALWAYS! Slider!SliderItem is 
a super class of Button!ButtonItem.


In fact, if we had some way to 

Re: D casting broke?

2016-06-19 Thread ag0aep6g via Digitalmars-d-learn

On 06/19/2016 09:59 PM, Joerg Joergonson wrote:

This should be completely valid since B!T' obviously derives from A!T
directly


ok


and we see that T' derives from b which derives from a
directly.


ok


So B!b is an entirely derived from A!a


No. B!b is derived from A!b, not from A!a. `b` being derived from `a` 
does not make A!b derived from A!a.


Here is the full inheritance tree:

X
├─x
│ └─a
│   └─b
├─A!a
└─A!b
  └─B!b


Re: D casting broke?

2016-06-19 Thread Adam D. Ruppe via Digitalmars-d-learn

On Sunday, 19 June 2016 at 19:59:28 UTC, Joerg Joergonson wrote:
This should be completely valid since B!T' obviously derives 
from A!T directly and we see that T' derives from b which 
derives from a directly. So B!b is an entirely derived from A!a 
and hence the cast should be successful


I don't see how you think that. Here's the parent chain:

B!b -> A!b -> X -> x -> Object

There's no A!a in there, the cast is failing correctly.

Just because `b` is a child of `a` doesn't mean that `A!b` is the 
same as `A!a`. Consider an array:


MyClass[] arr;
arr ~= new MyClass(); // ok cool

Object[] obj_arr = arr; // won't work! because...
obj_arr[0] = new RandomClass(); // this would compile...

// but obj_arr and arr reference the same data, so now:
arr[0] is typed MyClass... but is actually RandomClass! It'd 
crash horribly.




Array is just one example of where converting A!b to A!a is 
problematic. The same principle can apply anywhere, so it won't 
implicitly cast them.





The obviously question: Is there a simple way around this?


What are you actually trying to do?


D casting broke?

2016-06-19 Thread Joerg Joergonson via Digitalmars-d-learn

import std.stdio;

class X { X Parent; }

class x : X { }

class a : x
{
void Do()
{
auto p = cast(A!a)(this.Parent);  // works as long as we 
are in A

assert(p !is null);
}
}


class A(T : a) : X
{
X Parent = new X();
T _y = new T();
}

class b : a { }
class B(T : b) : A!T { }

void main(string[] argv)
{
auto _A = new A!a();
auto _B = new B!b();
_A.Parent = _A;
_A._y.Parent = _A;
_B.Parent = _B;// works if _A, since _B is of type _A it 
should still work

_B._y.Parent = _B; // ...

_A._y.Do();
_B._y.Do();

}


This should be completely valid since B!T' obviously derives from 
A!T directly and we see that T' derives from b which derives from 
a directly. So B!b is an entirely derived from A!a and hence the 
cast should be successful


So, my code crashes because when I do the cast in the base class 
A!T, and it is used in the derived class(which the cast should be 
valid), a null pointer is created which is used in the base 
class. (Basically, B!T doesn't have to have any code in it, just 
create the object, the code in A!T then will crash if such a cast 
exists)



The obviously question: Is there a simple way around this? I'd 
ask, how long to fix but that might take months/years. I can 
override in b and duplicate code but why? That makes life more 
difficult than having things work as they should(having to 
maintain twice is much code is not a solution).