D issues are now
tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Summary: |
Template Mixins do not work as advertised |
Product: |
D
|
Reporter: |
Andrew Livesay <andrew.livesay> |
Component: |
dmd | Assignee: |
No Owner <nobody> |
Status: |
RESOLVED
FIXED
|
Severity: |
critical
|
CC: |
akb825, bruno.do.medeiros+deebugz, bugzilla, clugdbug, dsimcha, k.hara.pg
|
Priority: |
P2
|
Keywords: |
accepts-invalid, patch |
Version: |
D2 |
Hardware: |
x86 |
OS: |
All |
// 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
Andrew Livesay
2009年03月17日 21:31:21 UTC
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
David Simcha
2010年09月08日 10:40:17 UTC
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
David Simcha
2010年09月08日 10:42:34 UTC
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 5
anonymous4
2010年12月03日 11:57:37 UTC
The right code can't be generated for such input.
(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.