19417, "stonea", "Unexpected behavior when trying to chain\cascade promoted method calls on an array of records.", "2022-03-11T00:14:23Z"
Method chaining is an idiom where methods modify and return the object itself so other methods can be called on the result (Method chaining - Wikipedia). This is commonly seen in Javascript API's among other contexts (for example: jQuery Chaining).
Trying to do this (with an array of records) in Chapel I came up with this example:
record C {
var prop : int;
proc init() { prop = 0; }
proc addOne() { prop += 1; return this; }
proc square() { prop = prop * prop; return this; }
}
var A: [0..<5] C;
forall i in 0..<5 do A[i].prop = i;
A.addOne().square();
writeln(A);
But this gives me a bunch of errors:
+ chpl foo.chpl -o foo
foo.chpl:10: error: const actual is passed to 'ref' formal 'this' of square()
foo.chpl:1: note: to formal of type C
foo.chpl:5: note: passed as ref here
foo.chpl:2: note: to ref formal here
foo.chpl:5: note: passed as ref here
foo.chpl:10: error: const actual is passed to 'ref' formal 'this' of square()
foo.chpl:1: note: to formal of type C
foo.chpl:5: note: passed as ref here
foo.chpl:2: note: to ref formal here
foo.chpl:5: note: passed as ref here
I can get this to work either having the methods explicitly return a copy of the object (and modify the A.addOne().square();
line to A = A.addOne().square()
, which is maybe the more sensible thing to do anyway) or by changing the methods to return by ref
intent.
But the error I'm getting confuses me, especially since if I try this on an individual element it works fine:
// This compiles fine:
A[1].addOne().square()
Although note that this will print 11 not 121 (suggesting that addOne() is returning is returning a copy of rather than a reference to the object). Perhaps we're returning it by const ref
by default, this example also would seem to indicate that:
record R {
var x = 42;
proc foo() {
return this;
}
}
proc inc(ref x: int) {
x += 1;
return x;
}
var myR: R;
inc(myR.foo().x);
writeln(myR); // prints 42
myR.foo().x += 1;
writeln(myR); // prints 42
Not sure what behavior we want\expect. But the original error confuses me.