Summary: covariance of out arguments and function subtyping
                    doesn't work
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: major
          Priority: P2
         Component: DMD

--- Comment #0 from Boscop <> 2012-03-09 08:17:46 PST ---
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:
    // Error: function test.fooB (out B b) is not callable using argument types
    // 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;
    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.

Configure issuemail:
------- You are receiving this mail because: -------

Reply via email to