On Fri, 21 Feb 2014 17:54:06 -0500, Frustrated <c1514...@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

Reply via email to