www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - autocall aka property for the millionth time

reply "Adam D. Ruppe" <destructionator gmail.com> writes:
I have one more solution to the property situation. This punts 
much of it to the library, but is actually easy to implement - I 
just added a proof of concept to a devel dmd in about 15 minutes.

Overview:

1) this is purely additive, changing nothing with existing code. 
Those are separate debates that I don't want to go over again.

2) Add an attribute  autocall that can be attached to functions. 
If an  autocall function is ever mentioned anywhere, in any 
context, it is rewritten foo -> foo().

Given that rewrite, it doesn't make sense for  autocall functions 
to take any arguments, since it is impossible to pass it any.

3) The rest of the details in making properties work are done by 
returning ref and/or helper structs.

Example:

struct S {
        int delegate(int) func()  autocall {
                 return (int b) {
                         printf("hello!\n");
                         return 10;
                 };
         }
}

S s;

auto a = s.func(10); // prints hello because s.func is 
automatically rewritten to s.func(), so this becomes s.func()(10);
static assert(is(typeof(a) == int); // passes


Boom, that's one of the three big issues for properties for me, 
solved.




What about setters? Last time I brought up this idea, setters are 
what killed me. Well, I'm sidestepping it this time. Here's how 
you could do that:


struct C {
    struct Property {
         int val;
         void opAssign(int a) { val = a; }
         int get() { return val; }
         alias get this;
    }

    private Property _prop;

    ref Property prop()  autocall {
         return _prop;
    }
}

C c;

int a = c.prop; // getter, works thanks to alias this (and if you 
used auto, it would be typed Property sure, but does it matter? 
It is still a value type btw despite being returned ref because 
the ref doesn't remain outside the direct use)

a += 5;

c.prop = a; // setter, via the helper's opAssign



You could also make c.prop += 5 work and so on by overloading the 
appropriate operators on the helper struct.

Overloads to opAssign let you do setters for various types too.



You might be thinking "blah, that's a little verbose". That's 
where std.typecons could come in, or a mixin template, or 
whatever. tbh I don't care, in the handful of cases where I want 
this (and indeed, it is a very small handful, since the existing 
D rules work fine in 95% of my cases), I'm return custom types 
anyway, so it is no trouble to me. (As it stands, I used exactly 
this pattern last time, with the only annoyance being if it is 
callable, having to write ()(arg)... which I often forget to do. 
It is so unnatural. Hence,  autocall)


But, with this pattern, the big items for properties are hit for 
me:

1) returning callables

2) a.prop += 5; // a.prop could return a ref struct with 
opOpAssign overloaded

3) hooking all the operations




And I'd like to remind everyone: this has ZERO effect on existing 
code. It breaks nothing, it requires no changes to anything 
except code we want to opt into this.



Walter, would you be willing to accept this?
Jul 04 2013
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 4 July 2013 at 15:26:45 UTC, Adam D. Ruppe wrote:
    ref Property prop()  autocall {
         return _prop;
    }

You might be wondering: what's the point of that over just having a "Property prop;"? The one thing I tend to want this for is some kind of dynamic type, where I use opDispatch to return a helper object from an AA: ref Property opDispatch(string name)() autocall { return this.properties[name]; } Which might also have extra code to insert it into the AA, or throw, etc. if needed. I don't think there's any way to do that without a function of some sort.
Jul 04 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 07/04/2013 05:26 PM, Adam D. Ruppe wrote:
 I have one more solution to the property situation. This punts much of
 it to the library, but is actually easy to implement - I just added a
 proof of concept to a devel dmd in about 15 minutes.

 Overview:

 1) this is purely additive, changing nothing with existing code. Those
 are separate debates that I don't want to go over again.

 2) Add an attribute  autocall that can be attached to functions. If an
  autocall function is ever mentioned anywhere, in any context, it is
 rewritten foo -> foo().

 Given that rewrite, it doesn't make sense for  autocall functions to
 take any arguments, since it is impossible to pass it any.

 3) The rest of the details in making properties work are done by
 returning ref and/or helper structs.
 ...

Doesn't work with type deduction. What about keeping property for setters and using autocall for getters to get rid of all the ambiguity?
Jul 04 2013
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 4 July 2013 at 15:37:42 UTC, Timon Gehr wrote:
 Doesn't work with type deduction.

meh, like I said, in the places I want this for myself, I'm using a custom struct anyway, so no worry there. In cases that return ints and strings, the optional parenthesis and a=5 rewrite to a(5) syntax is good enough for me, with the sole exception of the opOpAssign family of functions (a.prop += 5), and I've just learned to avoid doing that over the years.
 What about keeping  property for setters and using  autocall 
 for getters to get rid of all the ambiguity?

That was my first attempt (doing the autocall rewrite with property functions), but I failed to implement it because overload resolution and other difficulties. Perhaps being different attributes would help make that easier though.
Jul 04 2013