Bug 2740 – Template Mixins do not work as advertised
Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
All
Creation time
2009-03-17T21:13:00Z
Last change time
2015-06-09T05:11:54Z
Keywords
accepts-invalid, patch
Assigned to
nobody
Creator
andrew.livesay
Comments
Comment #0 by andrew.livesay — 2009-03-17T21:13:34Z
// As I understand TFM, all three calls to go() should be printing 'false'.
import std.stdio;
interface IFooable {
bool foo();
}
template TFoo() {
bool foo() { return true; }
}
class Foo : IFooable {
mixin TFoo;
bool foo() { return false; }
}
class _Foo : IFooable {
mixin TFoo;
}
class Foo2 : _Foo {
bool foo() { return false; }
}
class Foo3 : IFooable {
bool foo() { return false; }
}
void go(IFooable p) {
writefln(p.foo);
}
void main() {
Foo p = new Foo();
Foo2 p2 = new Foo2();
Foo3 p3 = new Foo3();
go(p); // output is "true" <------- Why isn't this false?
go(p2); // output is "false"
go(p3); // output is "false"
}
Comment #1 by andrew.livesay — 2009-03-17T21:31:21Z
Issue appears to be dependent on the order the mixin is imported. If you redefine foo() before "mixin TFoo;", it works as expected.
Comment #2 by dsimcha — 2010-09-08T10:40:17Z
This seems to happen iff the class is called from its interface handle:
import std.stdio;
interface IFooable {
bool foo();
}
mixin template TFoo() {
override bool foo() { return true; }
}
class Foo : IFooable {
mixin TFoo;
override bool foo() { return false; }
}
void go(IFooable p) {
writeln(p.foo);
}
void main() {
Foo p = new Foo();
go(p); // true
writeln(p.foo); // false
IFooable i = p;
writeln(i.foo); // true
}
Marking as critical because this is an extremely subtle wrong-code bug that can lead to some pretty frustrating debugging.
Comment #3 by dsimcha — 2010-09-08T10:42:34Z
Oh yeah, doesn't happen for abstract classes either. Looks like only the interface vtbl info is wrong.
import std.stdio;
abstract class IFooable {
abstract bool foo();
}
mixin template TFoo() {
override bool foo() { return true; }
}
class Foo : IFooable {
mixin TFoo;
override bool foo() { return false; }
}
void go(IFooable p) {
writeln(p.foo);
}
void main() {
Foo p = new Foo();
go(p); // false
writeln(p.foo); // false
IFooable i = p;
writeln(i.foo); // false
}
Comment #4 by bruno.do.medeiros+deebugz — 2010-12-03T06:33:18Z
Hum, I suspect the code above should not even compile. Instantiating the mixin "is analogous to cutting and pasting the body of the template into the location of the mixin." http://www.digitalmars.com/d/2.0/template-mixin.html
Thus it should be the same as:
class Foo : IFooable {
bool foo() { return false; }
bool foo() { return false; }
}
which should be a semantic error, I think. See http://d.puremagic.com/issues/show_bug.cgi?id=5312
Comment #5 by dfj1esp02 — 2010-12-03T11:57:37Z
The right code can't be generated for such input.
Comment #6 by akb825 — 2011-02-19T12:18:10Z
(In reply to comment #4)
> Hum, I suspect the code above should not even compile. Instantiating the mixin
> "is analogous to cutting and pasting the body of the template into the location
> of the mixin." http://www.digitalmars.com/d/2.0/template-mixin.html
> Thus it should be the same as:
>
> class Foo : IFooable {
> bool foo() { return false; }
> bool foo() { return false; }
> }
>
>
> which should be a semantic error, I think. See
> http://d.puremagic.com/issues/show_bug.cgi?id=5312
From http://www.digitalmars.com/d/2.0/template-mixin.html: "The declarations in a mixin are ‘imported’ into the surrounding scope. If the name of a declaration in a mixin is the same as a declaration in the surrounding scope, the surrounding declaration overrides the mixin one." In other words, declarations in the current scope always hide declarations in the mixin.