D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 7676 - covariance of out arguments and function subtyping doesn't work
Summary: covariance of out arguments and function subtyping doesn't work
Status: REOPENED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P4 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-03-09 08:17 UTC by Boscop
Modified: 2024-12-13 17:58 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Boscop 2012-03-09 08:17:46 UTC
The title says it all. Here is a test case (DMD 2.058):

---
// Functions are contravariant in their in-arguments
// and covariant in their out-arguments and return type.
// But DMD seems to ignore this:

import std.stdio;
class A {override string toString(){return "A";}}
class B : A {override string toString(){return "B";}}
void fooA(out A a) {a = new A;}
void fooB(out B b) {b = new B;}
string barA(A a) {return a.toString();}
string barB(B b) {return b.toString();}
void main() {
	A a = new A;
	a = new B; // correct covariant behavior
	assert(a.toString() == "B");

	// out arguments should be covariant, so this should work:
	fooB(a);
	// Error: function test.fooB (out B b) is not callable using argument types (A)
	// Error: cannot implicitly convert expression (a) of type test.A to test.B

	void function(out A) foo;
	foo = &fooA; // same type, trivial
	foo(a); assert(a.toString() == "A");

	// this should also work without a cast because
	// void function(out B) is a subtype of void function(out A)
	// due to the covariance of out arguments
	foo = &fooB;
	// Error: cannot implicitly convert expression (& fooB) of type void function(out B b) to void function(out A)
	// currently it only works with a cast:
	// foo = cast(void function(out A))&fooB;
	foo(a);
	assert(a.toString() == "B");

	B b = new B;
	assert(barA(b) == "B"); // correct contravariant behavior

	string function(B) bar;
	bar = &barB; // same type, trivial
	assert(bar(b) == "B");

	// string function(A) is a subtype of string function(B)
	// due to the contravariance of (in) arguments
	// so this should work:
	bar = &barA; // Error: cannot implicitly convert expression (& barA) of type string function(A a) to string function(B)
	// currently it only works with a cast:
	// bar = cast(string function(B))&barA;
	assert(bar(b) == "B");

	// this fails as it should, but for the wrong reason:
	fooA(b); // Error: cast(A)b is not an lvalue
	// it should fail because fooA's 1st argument is covariant and should therefore only accept supertypes of A (A is also a supertype of A), but B is a subtype of A
}
---

To me it seems that DMD treats out arguments as contravariant at first (which then fails due to the implicit cast resulting in an rvalue) and it seems to ignore covariance and contravariance for function subtyping.
Comment 1 Walter Bright 2012-03-09 11:14:29 UTC
This is an enhancement because D was not designed to deal with covariance for 'out' parameters, only covariance in return type.
Comment 2 mhh 2021-01-24 07:10:02 UTC
Spec/DIPfodder
Comment 3 dlangBugzillaToGithub 2024-12-13 17:58:56 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/18423

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB