www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Calling delegate properties without parens

reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
I have following code:

import std.array, std.range, std.stdio;

struct CommonInputRange(E)
{
      property bool delegate() empty;
      property E delegate() front;
     void delegate() popFront;
}

void main(string[] args)
{
     alias CommonInputRange!dchar DCRange;
     static assert(isInputRange!DCRange);
     DCRange dc;
     auto dcr = "abcdefg";
     auto t = dcr.takeExactly(3);
     dc.empty = &t.empty;
     dc.front = &t.front;
     dc.popFront = &t.popFront;

     for ( ; !dc.empty(); dc.popFront())
         writeln(dc.front());
}

As you can see in the for loop, range primitives must be called using 
parens (), otherwise they don't work.

Do you know if there are plans to implement  property for delegates and 
function pointers?
Apr 14 2012
next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 04/14/12 20:47, Piotr Szturmaj wrote:
 I have following code:
 
 import std.array, std.range, std.stdio;
 
 struct CommonInputRange(E)
 {
      property bool delegate() empty;
      property E delegate() front;
     void delegate() popFront;
 }
 
 void main(string[] args)
 {
     alias CommonInputRange!dchar DCRange;
     static assert(isInputRange!DCRange);
     DCRange dc;
     auto dcr = "abcdefg";
     auto t = dcr.takeExactly(3);
     dc.empty = &t.empty;
     dc.front = &t.front;
     dc.popFront = &t.popFront;
 
     for ( ; !dc.empty(); dc.popFront())
         writeln(dc.front());
 }
 
 As you can see in the for loop, range primitives must be called using parens
(), otherwise they don't work.
 
 Do you know if there are plans to implement  property for delegates and
function pointers?

property is for functions masquerading as data, i'm not sure extending it to pointers and delegates would be a good idea. What you are asking for is basically syntax sugar for: struct CommonInputRange(E) { bool delegate() _empty; property auto empty() { return _empty(); }; property auto empty(typeof(_empty) dg) { _empty = dg; }; E delegate() _front; property auto front() { return _front(); }; property auto front(typeof(_front) dg) { _front = dg; }; void delegate() popFront; } // [1] artur [1] which could also /almost/ be expressed as: struct PropDeleg(T) { T dg; property auto get() { return dg(); }; alias get this; void opAssign(T d) { dg = d; }; } struct CommonInputRange(E) { PropDeleg!(bool delegate()) empty; PropDeleg!(E delegate()) front; void delegate() popFront; } except this one would need an (implicit) conversion to get the same behavior. IOW it should work everywhere, as long as the result is assigned to a different type; ie you'd need "{ dchar c = dc.front; writeln(c); }" in the above example, because otherwise the writeln template will accept the struct, but never really use it, so the dchar conversion does not happen.
Apr 14 2012
next sibling parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Artur Skawina wrote:
  property is for functions masquerading as data, i'm not sure extending it
 to pointers and delegates would be a good idea. What you are asking for is
 basically syntax sugar for:

     struct CommonInputRange(E)
     {
         bool delegate() _empty;
          property auto empty() { return _empty(); };
          property auto empty(typeof(_empty) dg) { _empty = dg; };
         E delegate() _front;
          property auto front() { return _front(); };
          property auto front(typeof(_front) dg) { _front = dg; };
         void delegate() popFront;
     }

Yes, I was thinking about this, but it adds unnecessary overhead. I want to call delegates directly. I think the whole idea is harmless because semantically, from the user perspective, delegates and function pointers works just like normal functions. So, why not?
Apr 14 2012
parent Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Artur Skawina wrote:
 On 04/15/12 03:01, Piotr Szturmaj wrote:
 Artur Skawina wrote:
  property is for functions masquerading as data, i'm not sure extending it
 to pointers and delegates would be a good idea. What you are asking for is
 basically syntax sugar for:

      struct CommonInputRange(E)
      {
          bool delegate() _empty;
           property auto empty() { return _empty(); };
           property auto empty(typeof(_empty) dg) { _empty = dg; };
          E delegate() _front;
           property auto front() { return _front(); };
           property auto front(typeof(_front) dg) { _front = dg; };
          void delegate() popFront;
      }

Yes, I was thinking about this, but it adds unnecessary overhead. I want to call delegates directly.

The compiler has to implement it internally exactly like that anyway. D's design relies on such code being efficient - there is no preprocessor, no inline attribute and no macros. The trivial functions have to be inlined, if that doesn't happen it's a compiler bug. Once inlined, there's no overhead.

I wondered if properties can be inlined that way. But you have conviced me that indeed, inlining should help here. So, I'll use proxy properties. Thanks for your advice.
Apr 15 2012
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 04/15/12 03:01, Piotr Szturmaj wrote:
 Artur Skawina wrote:
  property is for functions masquerading as data, i'm not sure extending it
 to pointers and delegates would be a good idea. What you are asking for is
 basically syntax sugar for:

     struct CommonInputRange(E)
     {
         bool delegate() _empty;
          property auto empty() { return _empty(); };
          property auto empty(typeof(_empty) dg) { _empty = dg; };
         E delegate() _front;
          property auto front() { return _front(); };
          property auto front(typeof(_front) dg) { _front = dg; };
         void delegate() popFront;
     }

Yes, I was thinking about this, but it adds unnecessary overhead. I want to call delegates directly.

The compiler has to implement it internally exactly like that anyway. D's design relies on such code being efficient - there is no preprocessor, no inline attribute and no macros. The trivial functions have to be inlined, if that doesn't happen it's a compiler bug. Once inlined, there's no overhead.
 I think the whole idea is harmless because semantically, from the user
perspective, delegates and function pointers works just like normal functions.
So, why not?

I can see it being confusing and don't see much benefit - that's all. The current syntax is just a little more verbose, and mixins could be used if this scheme had to be used on a larger scale. artur
Apr 15 2012
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, April 14, 2012 20:47:20 Piotr Szturmaj wrote:
 I have following code:
 
 import std.array, std.range, std.stdio;
 
 struct CommonInputRange(E)
 {
       property bool delegate() empty;
       property E delegate() front;
      void delegate() popFront;
 }
 
 void main(string[] args)
 {
      alias CommonInputRange!dchar DCRange;
      static assert(isInputRange!DCRange);
      DCRange dc;
      auto dcr = "abcdefg";
      auto t = dcr.takeExactly(3);
      dc.empty = &t.empty;
      dc.front = &t.front;
      dc.popFront = &t.popFront;
 
      for ( ; !dc.empty(); dc.popFront())
          writeln(dc.front());
 }
 
 As you can see in the for loop, range primitives must be called using
 parens (), otherwise they don't work.
 
 Do you know if there are plans to implement  property for delegates and
 function pointers?

front returns an element in the range. In your case, it's returning a delegate, because you have a range of delegates. If front returned a class or struct with a member function called foo, which you wanted to call, then you'd be doing something like for(; !dc.empty; dc.popFront()) writeln(dc.front.foo()); But in your case, it's a delegate, so operating on that delegate means calling it, which means using the parens. dc.front just gives you the delegate, and it would be horrible if it did anything else. If front also called the delegate, the doing something like auto arr = arr(dc); would call each and every one of the delegates in the range, because it uses front to access the element _without calling it_. If there were some way to indicate that a delegate was called with property syntax, then you could no longer distinguish between simply returning the delegate and returning and call it. Not to mention, properties are supposed to be an abstraction that mimicks member variables. That makes no sense whatsoever with a delegate. And in this case, the member variable which _is_ being mimicked (front) happens to be a delegate. So, it makes perfect sense that you'd have to use parens on it to actually call it. - Jonathan M Davis
Apr 14 2012
parent Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Jonathan M Davis wrote:
 On Saturday, April 14, 2012 20:47:20 Piotr Szturmaj wrote:
 struct CommonInputRange(E)
 {
        property bool delegate() empty;
        property E delegate() front;
       void delegate() popFront;
 }

front returns an element in the range. In your case, it's returning a delegate, because you have a range of delegates.

Gah. That explains everything... Thanks!
Apr 15 2012