digitalmars.D.learn - opDispatch and property setters
- Lodovico Giaretta (68/68) Jun 21 2016 Hi,
- ag0aep6g (12/44) Jun 21 2016 [...]
- Lodovico Giaretta (8/19) Jun 21 2016 Thank you very much!
Hi, I'm trying to achieve perfect forwarding of any invocation from the wrapper to the wrapped item, but I'm having a bad time with property. Suppose this is my wrapper (with all logic stripped): struct Wrapper(T) { private T wrapped; template hasAssignableProperty(string name, Arg) { enum bool hasAssignableProperty = is(typeof( (ref T val, ref Arg arg) { mixin("val." ~ name ~ " = arg;"); })); } property void opDispatch(string name, Arg)(Arg arg) if (hasAssignableProperty!(name, Arg)) { pragma(msg, " property ", name, " ", Arg); mixin("return wrapped." ~ name ~ " = arg;"); } auto opDispatch(string name, Args...)(Args args) { static if (Args.length > 0) { pragma(msg, name, " ", Args); mixin("return wrapped." ~ name ~ "(args);"); } else { pragma(msg, name); mixin("return wrapped." ~ name ~ ";"); } } } It correctly handles any property, but the existence of the property setter dispatcher makes me unable to use any method that accepts just one parameter, because the compiler tries to resolve it with the first opDispatch overload, misinterpreting it as a setter call. Here is an example: struct Foo { private int _x; property int x() { return _x; } property void x(int newx) { _x = newx; } long foo(string a, double b) const { return 0; } void bar() {} int baz(int val) { return val; } // <-- method with exactly one argument } void main() { alias WrappedFoo = Wrapper!Foo; WrappedFoo wf; wf.x = 3; assert(wf.x == 3); long foores = wf.foo("hello", 3.14); wf.bar; int bazres = wf.baz(42); // ERROR: no property 'baz' (it's trying to use the first opDispatch overload, while the second would be ok) } Any way around this issue? Thank you in advance, and sorry if the question is silly and I'm just missing something stupid. Lodovico Giaretta
Jun 21 2016
On 06/21/2016 10:48 PM, Lodovico Giaretta wrote:struct Wrapper(T) { private T wrapped; template hasAssignableProperty(string name, Arg) { enum bool hasAssignableProperty = is(typeof( (ref T val, ref Arg arg) { mixin("val." ~ name ~ " = arg;"); })); } property void opDispatch(string name, Arg)(Arg arg) if (hasAssignableProperty!(name, Arg)) { pragma(msg, " property ", name, " ", Arg); mixin("return wrapped." ~ name ~ " = arg;"); } auto opDispatch(string name, Args...)(Args args) {[...]} }[...]struct Foo {[...]int baz(int val) { return val; } // <-- method with exactly one argument } void main() {[...]int bazres = wf.baz(42); // ERROR: no property 'baz' (it's trying to use the first opDispatch overload, while the second would be ok) } Any way around this issue?Works when you change the return type of the the property opDispatch to auto, so that it can return the result. It's a little weird, but D does support calling functions with assignment syntax. Alternatively, maybe you can actually check for the property attribute in hasAssignableProperty. See FunctionAttribute/functionAttributes in std.traits [1]. I haven't tested this.
Jun 21 2016
On Tuesday, 21 June 2016 at 21:11:39 UTC, ag0aep6g wrote:Works when you change the return type of the the property opDispatch to auto, so that it can return the result. It's a little weird, but D does support calling functions with assignment syntax. Alternatively, maybe you can actually check for the property attribute in hasAssignableProperty. See FunctionAttribute/functionAttributes in std.traits [1]. I haven't tested this.Thank you very much! I managed to get it to work by using this code: property auto opDispatch(string name, Arg)(Arg arg) { mixin("return _p_data." ~ name ~ " = arg;"); }It's a little weird, but D does support calling functions with assignment syntax.Definitely strange.
Jun 21 2016