constantsrefchapel

Behavior "ref" and "const ref" in Chapel


I am trying to understand the behavior of ref and const ref applied to the members of a composite type (e.g. record). Here, is it OK to assume that the behavior of them is similar to auto& and const auto& in C++? I.e., no copy will be created even for the const ref case? I wonder if there might be cases where the compiler can possibly create a temporary variable for const ref as a result of optimization (though I guess it will not happen).

To get some experience, I have tried the following code and confirmed that the addresses are the same for this simple case.

use CTypes;

record Foo {
  var n = 100;
}

var foo: Foo;
writeln("foo.n  : addr = ", c_ptrToConst(foo.n));

ref n_ref = foo.n;
writeln("n_ref  : addr = ", c_ptrToConst(n_ref));

const ref n_cref = foo.n;
writeln("n_cref : addr = ", c_ptrToConst(n_cref));
(Result)
foo.n  : addr = 0x654816445110
n_ref  : addr = 0x654816445110
n_cref : addr = 0x654816445110

Also, to check the address of data, is it reasonable to use c_ptrToConst() in the CTypes module to make a code similar to the following one in C++?

#include <iostream>
using namespace std;

struct Foo {
    int n = 100;
};

int main() {
    Foo foo;
    cout << "foo.n  : addr = " << &foo.n << endl;

    auto& n_ref = foo.n;
    cout << "n_ref  : addr = " << &n_ref << endl;

    const auto& n_cref = foo.n;
    cout << "n_cref : addr = " << &n_cref << endl;
}

A related question is: given that ref and const ref makes no copy, is there any performance difference between using an array component directly (say foo.arr) or using a ref variable to it (ref arr = foo.arr) for performing the same array calculation? (Here, foo is supposed to have an array component arr.)


Solution

  • It sounds to me like you've got the right idea. I think of ref and const ref in Chapel as being like a C pointer, but one that doesn't require a * to dereference or an & to establish. Initializing it points it to something (and it can't be re-pointed to something else later), and subsequent references to it are like dereferences of that pointer.

    Since Chapel supports distributed memory programming and a global namespace, Chapel references can refer to data stored in remote memories (e.g., on remote compute nodes) as well variables stored locally, and this makes them quite a bit more powerful than C/C++.

    Note that while your examples are using Chapel's type inference, which makes them similar to the auto cases you mention in C++, ref declarations in Chapel can be typed. For example:

    var x = 42;
    ref y: int = x;
    

    Here, Chapel is inferring x to be an int since it is initialized with an int literal. While y can similarly be inferred from x's type, here I'm asserting that it's a ref to an int. While this is obvious in a small case like this, such type annotations can be helpful as documentation or an assertion for code safety in cases where the initializing expression is more complex.

    I am reasonably certain that, today, the Chapel compiler will not create deep copies of variables being referred to by a const ref and would be surprised if we were to change this in the future. Specifically, doing so would seem to contradict what the user explicitly asked for. If Chapel were to do so in the future, I expect it would only be in cases where it served as an optimization where there'd be no way for a user to determine that we had done so (like your use of c_ptrToConst().

    To your other questions: