Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
January 13, 2009 Delegate contravariance | ||||
---|---|---|---|---|
| ||||
Is there any good reason why the following code doesn't work? The function "foo" requires as its argument a delegate that receives a B. This means that, because of the type soundness of the D language, the delegate will only be called with instances of B. Now, why can't it be "abc", then? The "abc" delegate just happens to handle more than it is required... class A { } class B : A { } void foo(void delegate(B b) dg) {} auto abc = (A a) { } auto qwe = (B b) { } void main() { foo(abc); // this line won't compile foo(qwe); } BTW: Same thing happens for const(B). B "sort of" a derivative of const(B), so it would make sense. Every possible argument that can be passed to a delegate(B) can also be passed to a delegate(A) or delegate(const(B)). Why the restriction, then? Am I missing something? |
January 13, 2009 Re: Delegate contravariance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Silvio Ricardo Cordeiro | "Silvio Ricardo Cordeiro" wrote
> Is there any good reason why the following code doesn't work?
> The function "foo" requires as its argument a delegate that
> receives a B. This means that, because of the type soundness
> of the D language, the delegate will only be called with instances
> of B. Now, why can't it be "abc", then? The "abc" delegate just
> happens to handle more than it is required...
>
>
> class A { }
> class B : A { }
> void foo(void delegate(B b) dg) {}
>
> auto abc = (A a) { }
> auto qwe = (B b) { }
>
> void main() {
> foo(abc); // this line won't compile
> foo(qwe);
> }
>
>
> BTW: Same thing happens for const(B). B "sort of" a derivative
> of const(B), so it would make sense. Every possible argument that can
> be passed to a delegate(B) can also be passed to a delegate(A) or
> delegate(const(B)). Why the restriction, then? Am I missing something?
I think it would be a worthy enhancement, but it currently isn't implemented or in the spec. You should add a bugzilla enhancement if it isn't already there.
You should be able to cast to get around it, but of course, that is ugly and cumbersome:
foo(cast(void delegate(B b))abc);
-Steve
|
January 13, 2009 Re: Delegate contravariance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Silvio Ricardo Cordeiro | Reply to Silvio,
> Is there any good reason why the following code doesn't work?
[...]
If you want to dive into template programming you can make a do-nothing function that does the cast and will only compile if the cast is in fact safe.
|
January 19, 2009 Re: Delegate contravariance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Silvio Ricardo Cordeiro | Silvio Ricardo Cordeiro wrote:
> Is there any good reason why the following code doesn't work?
> The function "foo" requires as its argument a delegate that
> receives a B. This means that, because of the type soundness
> of the D language, the delegate will only be called with instances
> of B. Now, why can't it be "abc", then? The "abc" delegate just
> happens to handle more than it is required...
>
>
> class A { }
> class B : A { }
> void foo(void delegate(B b) dg) {}
>
> auto abc = (A a) { }
> auto qwe = (B b) { }
>
> void main() {
> foo(abc); // this line won't compile
> foo(qwe);
> }
>
>
> BTW: Same thing happens for const(B). B "sort of" a derivative
> of const(B), so it would make sense. Every possible argument that can
> be passed to a delegate(B) can also be passed to a delegate(A) or
> delegate(const(B)). Why the restriction, then? Am I missing something?
Your code above is wrong, but you are right about a bug in dmd.
Your code sample should not compile because of two issues:
1. You're missing semicolons on the declarations of abc and qwe.
2. foo(abc) is implicitly requires casting A's to B's which is not guaranteed to be correct.
Here is code that should compile but doesn't
class A{}
class B:A{}
void foo(void delegate(A a) dg){}
auto abc = (A a){};
auto qwe = (B b){};
void main(){
foo(abc);
foo(qwe);
}
test.d(10): function test.foo (void delegate(A a) dg) does not match parameter types (void delegate(B b))
test.d(10): Error: cannot implicitly convert expression (qwe) of type void delegate(B b) to void delegate(A a)
|
January 19, 2009 Re: Delegate contravariance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jason House | Jason House wrote:
> Silvio Ricardo Cordeiro wrote:
>
>> Is there any good reason why the following code doesn't work?
>> The function "foo" requires as its argument a delegate that
>> receives a B. This means that, because of the type soundness
>> of the D language, the delegate will only be called with instances
>> of B. Now, why can't it be "abc", then? The "abc" delegate just
>> happens to handle more than it is required...
>>
>>
>> class A { }
>> class B : A { }
>> void foo(void delegate(B b) dg) {}
>>
>> auto abc = (A a) { }
>> auto qwe = (B b) { }
>>
>> void main() {
>> foo(abc); // this line won't compile
>> foo(qwe);
>> }
>>
>>
>> BTW: Same thing happens for const(B). B "sort of" a derivative
>> of const(B), so it would make sense. Every possible argument that can
>> be passed to a delegate(B) can also be passed to a delegate(A) or
>> delegate(const(B)). Why the restriction, then? Am I missing something?
>
> Your code above is wrong, but you are right about a bug in dmd.
>
> Your code sample should not compile because of two issues:
> 1. You're missing semicolons on the declarations of abc and qwe.
> 2. foo(abc) is implicitly requires casting A's to B's which is not guaranteed to be correct.
No, it implicitly casts Bs (derived) to As (base). The original example was correct (modulo semicolon issues). Your example has implicit casts of a base class to a derived class.
On the other hand, out parameters and return values have to be handled in the reverse manner, and ref parameters have to use exact matching.
|
Copyright © 1999-2021 by the D Language Foundation