Cannot implicitly convert derived type
Steven Schveighoffer
schveiguy at yahoo.com
Fri Feb 21 17:03:22 PST 2014
On Fri, 21 Feb 2014 17:54:06 -0500, Frustrated <c1514843 at 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
More information about the Digitalmars-d-learn
mailing list