New Issue: Unexpected behavior when trying to chain\cascade promoted method calls on an array of records.

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.