www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - opDispatch and property setters

reply Lodovico Giaretta <lodovico giaretart.net> writes:
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
parent reply ag0aep6g <anonymous example.com> writes:
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
parent Lodovico Giaretta <lodovico giaretart.net> writes:
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