Thread overview | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 21, 2014 Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
interface iGui { @property iButton button(ref iButton button); } class WindowsGui : iGui { WindowsButton _button; @property WindowsButton button(ref WindowsButton button) //@property iButton button(ref iButton button) { _button = button; return button; } } interface iButton { } class WindowsButton : iButton { } Should this not work? Error: class main.WindowsGui interface function 'iButton button(ref iButton button) @property' is not implemented Or by using the commented line: Error: cannot implicitly convert expression (button) of type main.iButton to main.WindowsButton 1. In the first case I override a property using a more derived type. This should work but doesn't. Seems D doens't support covariance properly? 2. In the second case, I can cast to make everything work. This seems wrong. Hence goto 1. WindowsGui is designed to only work with WindowsButton, say, and I should never have to use iButton in the WindowsGui class unless, maybe, I want to support non-windows buttons in the WindowsGui for some reason. Basically, because of the covariance issue I end up having to use a lot of casts. Hopefully theres some simple trick that won't pollute the code to make this work. I guess I could use a templated property with a generic type that is derivable from iButton to make it work? In some sense I can understand the error. If I'm using iGui then I have the option to use any button(since it is generic) but if iGui is a WindowsGui I'm not allowing this. The issue is, that I will have some type of dependency restrictions on the types. e.g., iGui g = new WindowsGui; g.button = new LinuxButton; // ok but not ok!! (should result in an error in some way) Obviously I can cast and check the type and do all that. Just feels like the wrong way to go about it because it requires a lot of casting and polluting the code with checks that in general, should be unnecessary. Again: In the WindowsGui I want to use WindowsButton, not iButton because WindowsGui will never need any other type of button. iButton is too general to use in WindowsGui. (it would be cool if one could do something like class WindowsGui : iGui iButton <= WindowsButton // constrains iButton to always be a WindowsButton. Checks/casts are automatically added by compiler when necessary { // use WindowsButton here with proper covariance relations and checks/casts } Anyways, hopefully there is some single trick to get what I'm asking? |
February 21, 2014 Re: Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frustrated | On 02/21/2014 02:54 PM, Frustrated wrote:
> interface iGui
> {
> @property iButton button(ref iButton button);
> }
>
> class WindowsGui : iGui
> {
> WindowsButton _button;
>
> @property WindowsButton button(ref WindowsButton button)
> //@property iButton button(ref iButton button)
> {
> _button = button;
> return button;
> }
> }
>
> interface iButton { }
> class WindowsButton : iButton { }
>
>
> Should this not work?
>
> Error: class main.WindowsGui interface function 'iButton
> button(ref iButton
> button) @property' is not implemented
>
> Or by using the commented line:
>
> Error: cannot implicitly convert expression (button) of type
> main.iButton to main.WindowsButton
>
>
> 1. In the first case I override a property using a more derived
> type. This should work but doesn't. Seems D doens't support
> covariance properly?
>
> 2. In the second case, I can cast to make everything work. This
> seems wrong. Hence goto 1. WindowsGui is designed to only work
> with WindowsButton, say, and I should never have to use iButton
> in the WindowsGui class unless, maybe, I want to support
> non-windows buttons in the WindowsGui for some reason.
>
> Basically, because of the covariance issue I end up having to use
> a lot of casts. Hopefully theres some simple trick that won't
> pollute the code to make this work. I guess I could use a
> templated property with a generic type that is derivable from
> iButton to make it work?
>
> In some sense I can understand the error. If I'm using iGui then
> I have the option to use any button(since it is generic) but if
> iGui is a WindowsGui I'm not allowing this. The issue is, that I
> will have some type of dependency restrictions on the types.
>
> e.g.,
>
> iGui g = new WindowsGui;
>
> g.button = new LinuxButton; // ok but not ok!! (should result in
> an error in some way)
>
> Obviously I can cast and check the type and do all that. Just
> feels like the wrong way to go about it because it requires a lot
> of casting and polluting the code with checks that in general,
> should be unnecessary. Again: In the WindowsGui I want to use
> WindowsButton, not iButton because WindowsGui will never need any
> other type of button. iButton is too general to use in WindowsGui.
>
> (it would be cool if one could do something like
>
> class WindowsGui : iGui
> iButton <= WindowsButton // constrains iButton to always be a
> WindowsButton. Checks/casts are automatically added by compiler
> when necessary
> {
> // use WindowsButton here with proper covariance relations and
> checks/casts
> }
>
> Anyways, hopefully there is some single trick to get what I'm
> asking?
It should not work because the derived type is requiring more than the interface. iGui requires that the parameter to button() is iButton:
@property iButton button(ref iButton button);
However, WindowsGui is bringing an extra requirement by asking a more specific iButton:
@property WindowsButton button(ref WindowsButton button)
Note that there is no problem with the return type because this time the derived type is still returning an iButton because WindowsButton "is an" iButton.
I don't know whether this works for you but I made the actual button a constructor parameter:
interface iGui
{
@property iButton button();
}
class WindowsGui : iGui
{
WindowsButton _button;
// The constructor gets the button
this(WindowsButton button)
{
this._button = button;
}
@property WindowsButton button()
{
return _button;
}
}
interface iButton { }
class WindowsButton : iButton { }
void main()
{
auto w = new WindowsGui(new WindowsButton());
w.button;
}
Ali
|
February 22, 2014 Re: Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Friday, 21 February 2014 at 23:19:19 UTC, Ali Çehreli wrote:
> On 02/21/2014 02:54 PM, Frustrated wrote:
>> interface iGui
>> {
>> @property iButton button(ref iButton button);
>> }
>>
>> class WindowsGui : iGui
>> {
>> WindowsButton _button;
>>
>> @property WindowsButton button(ref WindowsButton button)
>> //@property iButton button(ref iButton button)
>> {
>> _button = button;
>> return button;
>> }
>> }
>>
>> interface iButton { }
>> class WindowsButton : iButton { }
>>
>>
>> Should this not work?
>>
>> Error: class main.WindowsGui interface function 'iButton
>> button(ref iButton
>> button) @property' is not implemented
>>
>> Or by using the commented line:
>>
>> Error: cannot implicitly convert expression (button) of type
>> main.iButton to main.WindowsButton
>>
>>
>> 1. In the first case I override a property using a more derived
>> type. This should work but doesn't. Seems D doens't support
>> covariance properly?
>>
>> 2. In the second case, I can cast to make everything work. This
>> seems wrong. Hence goto 1. WindowsGui is designed to only work
>> with WindowsButton, say, and I should never have to use iButton
>> in the WindowsGui class unless, maybe, I want to support
>> non-windows buttons in the WindowsGui for some reason.
>>
>> Basically, because of the covariance issue I end up having to use
>> a lot of casts. Hopefully theres some simple trick that won't
>> pollute the code to make this work. I guess I could use a
>> templated property with a generic type that is derivable from
>> iButton to make it work?
>>
>> In some sense I can understand the error. If I'm using iGui then
>> I have the option to use any button(since it is generic) but if
>> iGui is a WindowsGui I'm not allowing this. The issue is, that I
>> will have some type of dependency restrictions on the types.
>>
>> e.g.,
>>
>> iGui g = new WindowsGui;
>>
>> g.button = new LinuxButton; // ok but not ok!! (should result in
>> an error in some way)
>>
>> Obviously I can cast and check the type and do all that. Just
>> feels like the wrong way to go about it because it requires a lot
>> of casting and polluting the code with checks that in general,
>> should be unnecessary. Again: In the WindowsGui I want to use
>> WindowsButton, not iButton because WindowsGui will never need any
>> other type of button. iButton is too general to use in WindowsGui.
>>
>> (it would be cool if one could do something like
>>
>> class WindowsGui : iGui
>> iButton <= WindowsButton // constrains iButton to always be a
>> WindowsButton. Checks/casts are automatically added by compiler
>> when necessary
>> {
>> // use WindowsButton here with proper covariance relations and
>> checks/casts
>> }
>>
>> Anyways, hopefully there is some single trick to get what I'm
>> asking?
>
> It should not work because the derived type is requiring more than the interface. iGui requires that the parameter to button() is iButton:
>
> @property iButton button(ref iButton button);
>
> However, WindowsGui is bringing an extra requirement by asking a more specific iButton:
>
> @property WindowsButton button(ref WindowsButton button)
>
> Note that there is no problem with the return type because this time the derived type is still returning an iButton because WindowsButton "is an" iButton.
>
> I don't know whether this works for you but I made the actual button a constructor parameter:
>
> interface iGui
> {
> @property iButton button();
> }
>
> class WindowsGui : iGui
> {
> WindowsButton _button;
>
> // The constructor gets the button
> this(WindowsButton button)
> {
> this._button = button;
> }
>
> @property WindowsButton button()
> {
> return _button;
> }
> }
>
> interface iButton { }
> class WindowsButton : iButton { }
>
> void main()
> {
> auto w = new WindowsGui(new WindowsButton());
> w.button;
> }
>
> Ali
But what about a setter? Using DI isn't the way to go here.
The point that in the windows class, it will only ever use a
windows button. This is fine, but because I'm using
iGui(programming to interfaces), it causes a problem inside the
windows class, which it shouldn't.
e.g., if I only had one gui and used one class, then there would
never be a problem.
Also, it is not a problem of construct, I already have a solution
by casting. But casting hides the fact that windowsgui is meant
to use only a windows button... which is obvious in the design.
Again
iGui uses an iButton
WindowsGui uses a WindowsButton
But when iGui is an actual WindowsGui, it forces WindowsGui to be
more generic than it is meant to be.
The key piece of information here is that I will only ever use
WindowsButtons with WindowsGui... this fact is not general and
the reason the compiler throws the error BUT it is always the
case in my code(except in errors).
I need to inform the compiler that it is always the case and then
I can do what I want.
|
February 22, 2014 Re: Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frustrated | On Fri, 21 Feb 2014 17:54:06 -0500, Frustrated <c1514843@drdrb.com> wrote: > interface iGui > { > @property iButton button(ref iButton button); > } > > class WindowsGui : iGui > { > WindowsButton _button; > > @property WindowsButton button(ref WindowsButton button) > //@property iButton button(ref iButton button) > { > _button = button; > return button; > } > } > > interface iButton { } > class WindowsButton : iButton { } > > > Should this not work? What you are trying to do is not legal. e.g.: class RogueButton : iButton { } iGui gui = new WindowsGui; gui.button = new RogueButton; Note that setting gui.button to any iButton is legal, but the derived type REQUIRES a WindowsButton. This would have to be rejected at runtime, because the compile-time type is implicitly convertible. There are two types of variance that are logical, contravariance and covariance. covariance allows you to *return* a more derived type than the base. In other words, this would be legal (assume same iButton/WindowsButton structure): interface iGui { @property iButton button(); } class WindowsGui : iGui { @property WindowsButton button() {...}; } This works, because whenever you return a WindowsButton, you ALSO are returning an iButton. In fact, D supports this. The opposite is contravariance, and that's used on *input* parameters. In this case, the derived method can accept a base of the parameter that the base class defines: interface iGui { void button(WindowsButton); // please humor me, I know you don't want to do this :) } class WindowsGui : iGui { void button(iButton); } This is logically sound, because the actual implementation only requires an iButton. Therefore, passing a WindowsButton into the iGui interface still satisfies that requirement. However, D does NOT support contravariance. > 2. In the second case, I can cast to make everything work. This > seems wrong. Hence goto 1. WindowsGui is designed to only work > with WindowsButton, say, and I should never have to use iButton > in the WindowsGui class unless, maybe, I want to support > non-windows buttons in the WindowsGui for some reason. This is actually the correct mechanism if you want to use polymorphism. However, in some cases, a templated system may be more advantageous than an interface system. One other possibility is to use overloading -- i.e.: class WindowsGui { @property WindowsButton button(WindowsButton b) { return _button = b;} @property WindowsButton button(iButton b) { if(auto wb = cast(WindowsButton)b) button = wb; else throw new ButtonException; } } This is not really an attractive solution, but it could be easily generated as a mixed-in solution. -Steve |
February 22, 2014 Re: Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frustrated | Generic?
"Frustrated" <c1514843@drdrb.com> ...
> interface iGui
> {
> @property iButton button(ref iButton button);
> }
>
> class WindowsGui : iGui
> {
> WindowsButton _button;
>
> @property WindowsButton button(ref WindowsButton button)
> //@property iButton button(ref iButton button)
> {
> _button = button;
> return button;
> }
> }
>
> interface iButton { }
> class WindowsButton : iButton { }
>
>
> Should this not work?
>
> Error: class main.WindowsGui interface function 'iButton
> button(ref iButton
> button) @property' is not implemented
> Or by using the commented line:
>
> Error: cannot implicitly convert expression (button) of type
> main.iButton to main.WindowsButton
>
> 1. In the first case I override a property using a more derived type. This should work but doesn't. Seems D doens't support covariance properly?
>
> 2. In the second case, I can cast to make everything work. This seems wrong. Hence goto 1. WindowsGui is designed to only work with WindowsButton, say, and I should never have to use iButton in the WindowsGui class unless, maybe, I want to support non-windows buttons in the WindowsGui for some reason.
>
> Basically, because of the covariance issue I end up having to use a lot of casts. Hopefully theres some simple trick that won't pollute the code to make this work. I guess I could use a templated property with a generic type that is derivable from iButton to make it work?
>
> In some sense I can understand the error. If I'm using iGui then I have the option to use any button(since it is generic) but if iGui is a WindowsGui I'm not allowing this. The issue is, that I will have some type of dependency restrictions on the types.
>
> e.g.,
>
> iGui g = new WindowsGui;
>
> g.button = new LinuxButton; // ok but not ok!! (should result in
> an error in some way)
>
> Obviously I can cast and check the type and do all that. Just feels like the wrong way to go about it because it requires a lot of casting and polluting the code with checks that in general, should be unnecessary. Again: In the WindowsGui I want to use WindowsButton, not iButton because WindowsGui will never need any other type of button. iButton is too general to use in WindowsGui.
>
> (it would be cool if one could do something like
>
> class WindowsGui : iGui
> iButton <= WindowsButton // constrains iButton to always be a
> WindowsButton. Checks/casts are automatically added by compiler
> when necessary
> {
> // use WindowsButton here with proper covariance relations and
> checks/casts
> }
>
> Anyways, hopefully there is some single trick to get what I'm asking?
|
February 22, 2014 Re: Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Saturday, 22 February 2014 at 01:03:22 UTC, Steven
Schveighoffer wrote:
> On Fri, 21 Feb 2014 17:54:06 -0500, Frustrated <c1514843@drdrb.com> wrote:
>
>> interface iGui
>> {
>> @property iButton button(ref iButton button);
>> }
>>
>> class WindowsGui : iGui
>> {
>> WindowsButton _button;
>>
>> @property WindowsButton button(ref WindowsButton button)
>> //@property iButton button(ref iButton button)
>> {
>> _button = button;
>> return button;
>> }
>> }
>>
>> interface iButton { }
>> class WindowsButton : iButton { }
>>
>>
>> Should this not work?
>
> What you are trying to do is not legal.
>
> e.g.:
>
> class RogueButton : iButton { }
>
> iGui gui = new WindowsGui;
> gui.button = new RogueButton;
>
> Note that setting gui.button to any iButton is legal, but the derived type REQUIRES a WindowsButton. This would have to be rejected at runtime, because the compile-time type is implicitly convertible.
>
> There are two types of variance that are logical, contravariance and covariance. covariance allows you to *return* a more derived type than the base. In other words, this would be legal (assume same iButton/WindowsButton structure):
>
> interface iGui
> {
> @property iButton button();
> }
>
> class WindowsGui : iGui
> {
> @property WindowsButton button() {...};
> }
>
> This works, because whenever you return a WindowsButton, you ALSO are returning an iButton. In fact, D supports this.
>
> The opposite is contravariance, and that's used on *input* parameters. In this case, the derived method can accept a base of the parameter that the base class defines:
>
> interface iGui
> {
> void button(WindowsButton); // please humor me, I know you don't want to do this :)
> }
>
> class WindowsGui : iGui
> {
> void button(iButton);
> }
>
> This is logically sound, because the actual implementation only requires an iButton. Therefore, passing a WindowsButton into the iGui interface still satisfies that requirement.
>
> However, D does NOT support contravariance.
>
>> 2. In the second case, I can cast to make everything work. This
>> seems wrong. Hence goto 1. WindowsGui is designed to only work
>> with WindowsButton, say, and I should never have to use iButton
>> in the WindowsGui class unless, maybe, I want to support
>> non-windows buttons in the WindowsGui for some reason.
>
> This is actually the correct mechanism if you want to use polymorphism. However, in some cases, a templated system may be more advantageous than an interface system.
>
> One other possibility is to use overloading -- i.e.:
>
> class WindowsGui
> {
> @property WindowsButton button(WindowsButton b) { return _button = b;}
>
> @property WindowsButton button(iButton b)
> {
> if(auto wb = cast(WindowsButton)b)
> button = wb;
> else
> throw new ButtonException;
> }
> }
>
> This is not really an attractive solution, but it could be easily generated as a mixed-in solution.
>
> -Steve
It is legal exactly because I will always guarantee that the
proper button will be used.
It is not logically legal as mentioned several times... no one
needs to mention that. But it is legal within the context of the
code. I'll never use a RogueButton so why force me to code for
the chance I might?
Again,
WindowsGui only uses WindowsButton which is a iButton type. So
why force me to always use iButton and cast it to WindowsButton?
Why can't I relax the condition to use the base type?
The only reason it is illegal is because I could use a
RogueButton, BUT I WON'T! If I do, then it is an error.
Basically, the point is, the compiler could enforce the above but
make the code more readable.
e.g.,
I do this:
@property WindowsButton button(WindowsButton b)
{
}
The compiler turns this into
@property WindowsButton button(iButton _b)
{
if (is(_b : WindowsButton)) assert(0, "Rogue button used");
auto b = cast(WindowsButton)_b;
}
One is very clean, the other is not. If by chance I use the wrong
button(a Rogue button) then it results in an error(hopefully user
controlled).
One allows me to program in a natural way while the other makes
me jump through hoops which litters the code with a bunch of
casts and checks which are only there in the odd event that I
assign the wrong type(which, I'm not going to do on purpose).
Again, the whole point of why it is illegal because you can pass
a RogueButton... BUT I DON'T INTEND TO PASS THEM! If I could
absolutely guarantee that I won't pass them then there should be
no problem(no asserts). Since I can't guarantee it I have to
litter my code with checks? The compiler could do this for me.
|
February 22, 2014 Re: Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Eric Suen | On Saturday, 22 February 2014 at 05:20:25 UTC, Eric Suen wrote:
> Generic?
>
I don't see how this would help. I'd have to specify every
concrete type in the creation of the object which might be
significant. I can't use a generic virtual method so that doesn't
help either.
It would be nice to have something like
T foo(T : iButton)(T button);
Which then I override with
WindowsButton foo(WindowsButton button) { }
Since WindowsButton is derived from iButton. The compiler would
have to insert a type check to make sure when I called the first
one(from the interface) that it was a windows button that was
passed(since any iButton could be passed) when using the
WindowsGui.
The main point of all this is simply efficiency. I have to liter
the code with checks and casts when it is entirely possible to
get the compiler to automate it all. By doing so one can program
the concrete class in a much more natural way.
|
February 23, 2014 Re: Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frustrated | On Sat, 22 Feb 2014 15:17:37 -0500, Frustrated <c1514843@drdrb.com> wrote: > It is legal exactly because I will always guarantee that the > proper button will be used. Static typing says it's not legal. D does not do dynamic type checking upon calling virtual functions. > It is not logically legal as mentioned several times... no one > needs to mention that. But it is legal within the context of the > code. I'll never use a RogueButton so why force me to code for > the chance I might? You may not be the only one using WindowsGui. You can't guarantee other code won't do it. In any case, the compiler cannot possibly know your intentions. > Basically, the point is, the compiler could enforce the above but > make the code more readable. > > e.g., > > I do this: > > @property WindowsButton button(WindowsButton b) > { > > } > > The compiler turns this into > > @property WindowsButton button(iButton _b) > { > if (is(_b : WindowsButton)) assert(0, "Rogue button used"); > auto b = cast(WindowsButton)_b; > > } This solution is not as efficient as the one I outlined. If you have a WindowsGui object, no need to accept iButton when you require WindowsButton. > One allows me to program in a natural way while the other makes > me jump through hoops which litters the code with a bunch of > casts and checks which are only there in the odd event that I > assign the wrong type(which, I'm not going to do on purpose). Sorry, if you want a dynamically typed language, use one. D is not that. > Again, the whole point of why it is illegal because you can pass > a RogueButton... BUT I DON'T INTEND TO PASS THEM! If I could > absolutely guarantee that I won't pass them then there should be > no problem(no asserts). Since I can't guarantee it I have to > litter my code with checks? The compiler could do this for me. You can't guarantee it. That is the point. The compiler could do the checks for you, but D is not dynamically typed. The best you can do is encapsulate the type checking code as a mixin. -Steve |
February 23, 2014 Re: Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frustrated | On 02/22/2014 12:17 PM, Frustrated wrote: > Again, the whole point of why it is illegal because you can pass > a RogueButton... BUT I DON'T INTEND TO PASS THEM! Thinking that way, many rules of a statically type-checked language like D would be unnecessary. ;) > WindowsGui only uses WindowsButton which is a iButton type. WindowsGui is totally free to use any type it wants. However, it cannot both claim to implement an interface without actually obeying its requirements. > Why can't I relax the condition to use the base type? The users of iGui don't even know what a WindowsButton is: interface iGui { @property iButton button(ref iButton button); } Imagine the following that I write: void foo(WindowsGui gui, iButton b) { gui.button(b); } Is the call legal or not? How would I know and why should I care? I have a WindowsGui, which happens to be an iGui and I have an iButton. According to the contract of the interface I should be able to call it without fear of type problems. Even, I can create my own iButton and pass it to that WindowsGui: gui.button(new MyButton()); I should be able to do all of that just because WindowsGui promises to be an iGui. Getting back to what I said above: WindowsGui is totally free to use any type it wants. That's why both Steven and I made it take its button as a constructor parameter. Then, you also mentioned a setter. That's fine too. As long as WindowsGui allows me to give it an iButton when I call button(), it is all fine. Ali |
February 23, 2014 Re: Cannot implicitly convert derived type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frustrated | interface iButton { }
class WindowsButton : iButton { }
interface iGui(T)
{
@property T button(ref T button);
}
class WindowsGui : iGui!(WindowsButton)
{
@property WindowsButton button(ref WindowsButton button) {
return button;
}
}
"Frustrated" <c1514843@drdrb.com>
> On Saturday, 22 February 2014 at 05:20:25 UTC, Eric Suen wrote:
>> Generic?
>>
>
> I don't see how this would help. I'd have to specify every concrete type in the creation of the object which might be significant. I can't use a generic virtual method so that doesn't help either.
>
> It would be nice to have something like
>
> T foo(T : iButton)(T button);
>
> Which then I override with
>
> WindowsButton foo(WindowsButton button) { }
>
> Since WindowsButton is derived from iButton. The compiler would have to insert a type check to make sure when I called the first one(from the interface) that it was a windows button that was passed(since any iButton could be passed) when using the WindowsGui.
>
> The main point of all this is simply efficiency. I have to liter the code with checks and casts when it is entirely possible to get the compiler to automate it all. By doing so one can program the concrete class in a much more natural way.
>
>
|
Copyright © 1999-2021 by the D Language Foundation