www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Bug? Function pointer/delegate types are not covariant

reply Andy Friesen <andy ikagames.com> writes:
     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
Jul 20 2004
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
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.
Jul 21 2004
parent Andy Friesen <andy ikagames.com> writes:
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
Jul 21 2004