Thread overview
Bug? Function pointer/delegate types are not covariant
Jul 20, 2004
Andy Friesen
Jul 21, 2004
Stewart Gordon
Jul 21, 2004
Andy Friesen
July 20, 2004
    import std.stdio;

    class Base {}
    class Derived : Base {}

    void fooBase(Base b) { writefln("Base!"); }
    void fooDerived(Derived d) { writefln("Derived!!"); }

    int main() {
        void function(Base b) myFunc = &fooDerived; // boom.
        myFunc(new Derived());
        return 0;
    }

An explicit cast appears to solve the problem, but but it may not work in the general case due to ABI considerations.  Also, it makes for somewhat cumbersome interfaces.

 -- andy
July 21, 2004
Andy Friesen wrote:
<snip>
>     void fooDerived(Derived d) { writefln("Derived!!"); }
> 
>     int main() {
>         void function(Base b) myFunc = &fooDerived; // boom.
>         myFunc(new Derived());
>         return 0;
>     }

function(Derived) isn't a specific case of a function(Base).  A function(Base) is a function that accepts an arbitrary Base object as its argument.  A function(Derived) doesn't accept an arbitrary Base object as its argument.  If you assigned a function(Derived) to a function(Base) pointer, and then called it with a Base that isn't a Derived, what would be supposed to happen?

Quite the opposite, if there should be any covariance in function parameters, it should work the other way.  A void function(Base) would be assignable to a void function(Derived), but not vice versa.

This is the reverse of return type covariance, by nature.  With this idea, a Base function(Derived) pointer would be able to take a function of any of these signatures:

Base function(Derived)
Derived function(Derived)
Derived function(Object)
Base function(Base)
Derived function(Base)
Derived function(Object)

> An explicit cast appears to solve the problem, but but it may not work in the general case due to ABI considerations. Also, it makes for somewhat cumbersome interfaces.

What kind of "somewhat cumbersome interfaces" are we talking of here?

Stewart.

-- 
My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment.  Please keep replies on the 'group where everyone may benefit.
July 21, 2004
Stewart Gordon wrote:

> This is the reverse of return type covariance, by nature.  

doh.  I should have seen that..

>> An explicit cast appears to solve the problem, but but it may not work in the general case due to ABI considerations. Also, it makes for somewhat cumbersome interfaces.
> 
> 
> What kind of "somewhat cumbersome interfaces" are we talking of here?

I was fiddling with the possibility of an automatic way to set up dynamically dispatching functions for multimethods and so forth, which led me to the desire to implement it like so:

    void handleAddExpression(AddExpression a) { ... }
    void handleMulExpression(MulExpression m) { ... }

    void handleExpression(Expression e) {
        // automagically relay to the proper method
        // based on the type of e
    }

It's pretty simple: get classinfo for a type, index into an associative array for the proper function, then call.

The trick is filling up that associative array. :)  Requiring a cast is a bit of a drag, but clearly the right thing, as you've demonstrated.

 -- andy