D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 10103 - template mixin with property overloads
Summary: template mixin with property overloads
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 normal
Assignee: No Owner
URL:
Keywords: pull, rejects-valid
Depends on:
Blocks:
 
Reported: 2013-05-17 02:31 UTC by Sebastian Graf
Modified: 2013-10-24 02:21 UTC (History)
1 user (show)

See Also:


Attachments
Alternative example of problem (339 bytes, text/x-dsrc)
2013-10-23 23:39 UTC, Joseph Rushton Wakeling
Details
Second example of bug still in existence (339 bytes, text/x-dsrc)
2013-10-23 23:40 UTC, Joseph Rushton Wakeling
Details

Note You need to log in before you can comment on or make changes to this issue.
Description Sebastian Graf 2013-05-17 02:31:31 UTC
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 2 github-bugzilla 2013-05-20 09:13:01 UTC
Commits pushed to master at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/e892946b376b8365bc6cefd896e5e3e6a1219b16
fix Issue 10103 - template mixin with property overloads

https://github.com/D-Programming-Language/dmd/commit/fa4a52c8e832f43081349332ea3d274d976c54ca
Merge pull request #2047 from 9rnsr/fix10103

Issue 10103 - template mixin with property overloads
Comment 3 github-bugzilla 2013-05-29 18:25:59 UTC
Commit pushed to 2.063 at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/76d09dfa5ef28176f666aa6f50038ed6a48b830b
Fix 2.063 branch breaking

Bug10103 is not yet fixed in 2.063 branch.
Comment 5 Joseph Rushton Wakeling 2013-10-23 23:39:05 UTC
Created attachment 1281 [details]
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 Joseph Rushton Wakeling 2013-10-23 23:40:30 UTC
Created attachment 1282 [details]
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 Joseph Rushton Wakeling 2013-10-23 23:42:49 UTC
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 Kenji Hara 2013-10-24 00:37:15 UTC
(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 Joseph Rushton Wakeling 2013-10-24 02:21:52 UTC
Thanks for the explanation, Kenji -- apologies for the misunderstanding, but at least we now have this special case documented here :-)