Issue 4511 - Contravariance problem
Summary: Contravariance problem
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 critical
Assignee: No Owner
URL:
Keywords: accepts-invalid, patch
Depends on:
Blocks: 2573
  Show dependency treegraph
 
Reported: 2010-07-26 13:35 UTC by bearophile_hugs
Modified: 2011-11-08 02:20 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description bearophile_hugs 2010-07-26 13:35:11 UTC
A problem found by Jesse Phillips. This is Java program:


class Base {}

class Derived extends Base {}

abstract class Abstract {
    abstract Base foo();
}

class Concrete extends Abstract {
     @Override Derived foo() {
        return new Base();
    }
}

class Test {}



The javac compiler prints:


Test.java:11: incompatible types
        return new Base();
               ^
  required: Derived
  found:    Base
1 error



But dmd 2.047 compiles this D2 program with no errors:

class Base {}

class Derived : Base {}

abstract class Abstract {
    abstract Base foo();
}

class Concrete : Abstract {
    override Derived foo() {
        return new Base;
    }
}

void main() {}
Comment 1 Michal Minich 2010-12-09 01:16:45 UTC
Slightly extended example shows that the returned instance is of type derived!, but constructor is not called.

class Base {}

class Derived : Base { this () { x = 1; }  int x; }

abstract class Abstract {
    abstract Base foo();
}

class Concrete : Abstract {
    override Derived foo() {
        return new Base;
    }
}

void main() {
    auto c = new Concrete;
    auto x = c.foo();
    writeln (typeof(x).stringof); // prints Derived (even it is result of 'new Base')
    writeln (x.x); // prints 0 (wich means Derived's constructor is not called)
    x.x = 2;
    writeln (x.x); // prints 2
}
Comment 2 anonymous4 2010-12-09 11:27:03 UTC
>     auto c = new Concrete;
>     auto x = c.foo();
>     writeln (typeof(x).stringof); // prints Derived (even it is result of 'new
> Base')

You're doing it wrong.
typeof(x) is evaluated at compile time and always gives the declared type even if x==null

The correct code is
---
auto c = new Concrete;
auto x = c.foo();
writeln(x.classinfo.name); // Base
---
Comment 3 anonymous4 2010-12-09 11:31:30 UTC
>     x.x = 2;
>     writeln (x.x); // prints 2

This just writes to the memory after the allocated Base object, probably corrupting heap.