Setter chaining

DigitalDesigns DigitalDesigns at gmail.com
Wed May 30 20:42:28 UTC 2018


On Wednesday, 30 May 2018 at 15:46:36 UTC, Steven Schveighoffer 
wrote:
> On 5/30/18 10:49 AM, DigitalDesigns wrote:
>> Does it sound good?
>> 
>> class X
>> {
>>     double x;
>>     @property X foo(double y) { x = y; return this; }
>> 
>>     @property X bar(double y) { x = y + 5; return this; }
>> }
>> 
>> void main()
>> {
>>      X x = new X();
>>      x.foo(3).bar(4);
>> }
>> 
>> 
>> It sort of emulates UFCS but I'm not sure if it's more trouble 
>> than it's worth.
>> 
>> 
>> I figure it would be better than just returning void as it 
>> provides the option to chain but not sure if it will come back 
>> to bite me.
>
> Yes, I do this kind of stuff, but you need to word your 
> functions correctly.
>
> I would avoid @property there, as this implies you should use 
> it like:
>
> x.foo = 5;
>
> and if you return a reference to the type itself, it will read 
> weird if you do it that way:
>
> auto five = (x.foo = 5);
>
> Here the name of the function is really really important.
>
> In my use case, I am kind of using it in an SQL builder type, 
> where each time you call a method it adds some piece of the 
> query. Like:
>
> auto query = table.select("id, name").where("foo = 
> 5").orderBy("name");
>
> -Steve

Well, what I mean is to be able to have the ability to assign 
like a field or a function.


sometimes I might want to use it as a property like

x.foo = 5;

and sometimes like a method

x.foo(5).foo(8);

for chaining.

Rather than having to to create setfoo and such.

Since D allows both syntaxes to be used, rather than returning 
void, turning parenting object allows the chaining to take place.

Since the trick here is to be consistent, all setters must follow 
this principle, it shouldn't be a problem with consistency.

>
> auto five = (x.foo = 5);

I wouldn't do that,just doesn't look right but I see your point.

What would be cool is if D had some special way to return the 
object of the class the setter was in.

auto x = (@x.foo = 5);

Here @ returns x but first computes x.foo = 5;.

In a way, it is like "this". @ gets the "this" of the function. 
Could work on any function:

class Y
{
    void foo();
    @property int baz();
    @property double bar(int x);
}

y. at foo() returns y;
y. at baz() returns y;
y. at bar(3) returns y;

Essentially one could few all functions as returning this and the 
value in a tuple and be default the value is returned and using a 
"selector" character will return this.

class Y
{
    Tuple!(void, typeof(this)) foo();
    Tuple!(int, typeof(this)) baz();
    Tuple!(double, typeof(this)) bar(int x);
}

y.foo()[1] returns y;
...

The compiler could simplify all this and by putting this in a 
register it could be be quite fast. In fact, since these are 
member functions and this is passed it will just fall through so 
very little overhead. The compiler can also optimize the code. 
Might take a bit to verify all the corner cases but would 
probably be useful once people could use it and get used to it.

@, $, |, ?, ! or many symbols could be used without ambiguity 
because a dot will always preceded them.










More information about the Digitalmars-d-learn mailing list