Comment #0 by SebastianGraf — 2013-05-17T02:31:31Z
If you mix in getters and setters in seperate template mixins, it fails to compile on first property-like usage.
Strangely, you may use both overloads if you treat them like functions (e.g. the first examples in main below).
I think this is related to http://d.puremagic.com/issues/show_bug.cgi?id=1686 and http://d.puremagic.com/issues/show_bug.cgi?id=9235.
Offending code:
mixin template Getter() {
@property auto x() { return _x; }
}
mixin template Setter() {
@property void x(int x) { _x = x; }
}
struct Foo {
int _x;
mixin Getter!(); // definition order is irrelevant
mixin Setter!();
}
void main() {
auto f = Foo(4);
auto x1 = f.x(); //fine
f.x(2); // fine
auto x2 = f.x; // Error: expression has no value
f.x = 3; // Error: f.x is not an lvalue
}
Comment #5 by joseph.wakeling — 2013-10-23T23:39:05Z
Created attachment 1281
Alternative example of problem
The problem does not appear to be resolved in all cases. See attached code, where a class takes _one_ of the implementations (getter _or_ setter) via a mixin, and the other is local.
Comment #6 by joseph.wakeling — 2013-10-23T23:40:30Z
Created attachment 1282
Second example of bug still in existence
This second example has the _getter_ obtained via mixin, while the setter is in the class itself.
Comment #7 by joseph.wakeling — 2013-10-23T23:42:49Z
The current fix does not cover all possible cases. The two recently-attached examples show cases where, of a getter/setter property pair, a class implements one of them locally and obtains the other via a mixin. In both cases errors result:
$ rdmd mixproperty.d
mixproperty.d(30): Error: a.foo is not an lvalue
$ rdmd mixproperty2.d
mixproperty2.d(31): Error: function mixproperty2.A.foo (const(int) f) is not callable using argument types ()
Comment #8 by k.hara.pg — 2013-10-24T00:37:15Z
(In reply to comment #7)
> The current fix does not cover all possible cases. The two recently-attached
> examples show cases where, of a getter/setter property pair, a class implements
> one of them locally and obtains the other via a mixin. In both cases errors
> result:
>
> $ rdmd mixproperty.d
> mixproperty.d(30): Error: a.foo is not an lvalue
>
> $ rdmd mixproperty2.d
> mixproperty2.d(31): Error: function mixproperty2.A.foo (const(int) f) is
> not callable using argument types ()
No. The two cases does not work as you expected. **It's by design**.
mixin template B()
{
void foo(int n) {}
}
class C
{
void foo() {}
// Mixed-in symbol foo(int) won't be automatically merged with foo().
// In other words, C.foo() hides C.B!().foo(int) normally.
mixin B;
}
void main()
{
auto c = new C;
c.foo(); // OK
c.foo(1); // NG, foo() is not callable using argument types (int)
}
If you want to make workable both c.foo() and c.foo(1), you need to change the mixin declaration as follows.
class C
{
...
mixin B x;
alias foo = x.foo; // merge foo(int) in the overload set 'C.foo'
}
void main()
{
auto c = new C;
c.foo(); // OK
c.foo(1); // OK
}
I know that currently D does not have a feature to do it automatically. If you want to do it, you could design a language enhancement to resolve the issue.
Change back the issue status.
Comment #9 by joseph.wakeling — 2013-10-24T02:21:52Z
Thanks for the explanation, Kenji -- apologies for the misunderstanding, but at least we now have this special case documented here :-)