# Ref members of class/record

**URL:** <https://chapel.discourse.group/t/ref-members-of-class-record/46782>\
**Category:** Users\
**Created:** [December 18, 2025, 1:40pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782 "2025-12-18T13:40:10Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![jmag722](https://avatars.discourse-cdn.com/v4/letter/j/bbce88/32.png) [@jmag722](https://chapel.discourse.group/u/jmag722)\
**Post date:** [December 18, 2025, 1:40pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/1 "2025-12-18T13:40:10Z")

</div>

Came across the message today:

`"References cannot be members of classes or records yet."`

Is there a status for this feature? Github issue?

It would be nice for constructing large custom data structures (trees).

---

<div class="post-metadata">

**Author:** ![jabraham](https://yyz2.discourse-cdn.com/free1/user_avatar/chapel.discourse.group/jabraham/32/430_2.png) [@jabraham](https://chapel.discourse.group/u/jabraham)\
**Post date:** [December 18, 2025, 4:34pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/2 "2025-12-18T16:34:31Z")

</div>

The github issue is [Timeline for ref Fields in Classes/Records? · Issue #8481 · chapel-lang/chapel · GitHub](https://github.com/chapel-lang/chapel/issues/8481), which is pretty old and hasn't been updated in awhile. I think you should comment your use case there.

-Jade

---

<div class="post-metadata">

**Author:** ![bradcray](https://yyz2.discourse-cdn.com/free1/user_avatar/chapel.discourse.group/bradcray/32/72_2.png) [@bradcray](https://chapel.discourse.group/u/bradcray)\
**Post date:** [December 18, 2025, 5:17pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/3 "2025-12-18T17:17:06Z")

</div>

Hi Jared —

I'd really like `ref` fields in classes and records as well—of the language features that I'd consider to be "missing" today, I think it's priority #1 on my list.

To try and avoid having you be blocked by this feature, though, I wanted to note that for large custom data structures like trees, the typical approach in Chapel would be to use class fields to have one object point to another. I think even if there were `ref` fields, this would be a preferable way to write such data structures because classes provide options that can lead to better discipline for memory management (classes can be `owned`, `shared`, or `borrowed` in addition to `unmanaged`) and nilability (class variables can be declared such that `nil` is or is not a legal value). In contrast, `ref`s are a bit more restricted while also not providing memory management guarantees beyond what the compiler can prove statically.

An example of using classes in this way that quickly comes to mind is the "binary trees" benchmark from the computer language benchmark game, where a fairly straightforward version is available here: [binary-trees Chapel&nbsp;#4 program (Benchmarks Game)](https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/binarytrees-chapel-4.html)

Note that this uses the "least safe" class-based option in that the class fields are nilable (to support leaf nodes with no children) and `unmanaged` (to meet the benchmark's requirements about how memory is freed, I believe? In production codes, `owned` would probably be a nicer choice).

If we had `ref` fields, I think it would be challenging to write this benchmark's tree pattern to use them because Chapel doesn't have a notion of `nil`/`NULL` `ref`s which would be necessary to represent the leaf nodes. There might be ways to work around this, such as creating a sentinel `nulltreeNode` object that all leaf nodes referred to, but then that leads to a challenge about what its children would point to… (in the sense that I'm not confident we'd be able to create an object whose ref fields referred to itself). Classes seem more naturally designed for this kind of pattern in Chapel to me.

If there are other patterns or classes that would help show how they could be used for such data structures, please let us know.

-Brad

---

<div class="post-metadata">

**Author:** ![jmag722](https://avatars.discourse-cdn.com/v4/letter/j/bbce88/32.png) [@jmag722](https://chapel.discourse.group/u/jmag722)\
**Post date:** [December 19, 2025, 12:34am UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/4 "2025-12-19T00:34:42Z")

</div>

Thank you for your reply. This was good to help me think about what I want.

I think a good example of this could be a k-d tree. It’s a binary tree where nodes represent different dimensional values in a k-dimensional input set (a point cloud or something). If this point cloud were very large, it’s likely going to be generated outside the KDTree class (or should be), or read in from a file. But at the end of the day, the resultant data remains a multidimensional array. Moreover, a lightweight tree doesn’t necessarily consume the data, but rather refers to it (tree nodes could store indices of the points, rather than copying point values).

I see a few workarounds to the `ref`-in-a-class issue:

1. wrap the array in a dedicated Data class. but then the Data class has the same issue with copying. But at least this class could have the dedicated method to generate/read the data somehow, though that puts the burden of data generation on the implementation
2. move the memory from the outside array into the class directly, rather than copy (`MemMove`?). but then if the dataset is needed or used outside this would be an undesirable side-effect
3. drop the classes, and have a purely functional interface to the tree. More book-keeping for the user though and can lead to a messier API
4. use a `c_ptr`
5. as is probably appropriate in 90% of cases, copy and be done with it haha

What do you think?

---

<div class="post-metadata">

**Author:** ![bradcray](https://yyz2.discourse-cdn.com/free1/user_avatar/chapel.discourse.group/bradcray/32/72_2.png) [@bradcray](https://chapel.discourse.group/u/bradcray)\
**Post date:** [December 19, 2025, 1:54am UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/5 "2025-12-19T01:54:09Z")

</div>

Hi Jared —

When you say "has the same issue with copying" is your concern that class assignments would result in deep copies in Chapel? They don't, so for example, code like the following:

```chapel
class Data {
  var buff: [1..n, 1..n, 1..n] real;

  proc init(filename: string) { … }

  proc init(data: [1..n, 1..n, 1..n] real) { … }
}

var myData = new shared Data(filename="infile.dat"); // or maybe we'd want to use `owned` and have the following references to `myData` `.borrow()` from it.
var bradsData = myData;

class Node {
  var d: Data;
}

var nd = new Node(d = myData);

```

only creates one n^3 array, created by the `new Data(…)` expression. The other class declarations (`bradsData`, `nd.d`) are simply pointing to that same object, so not creating their own n\*\*3 arrays. In this sense, classes are referential by nature. In contrast, Chapel records use deep-copy semantics by default and would result in three n^3 arrays if we were to replace `class` with `record` above (and remove the `shared` keyword).

In cases where users do want a deep-copy of classes, one way to do that is to create an explicit copy method—e.g., `proc Data.copy() { return new Data(data = this.data; }` and then invoke it explicitly (e.g., `var jaredsData = bradsData.copy();`).

If I've misunderstood what you meant by "the same issue with copying", please help me understand what you meant—this was my best guess.

Thanks,  
-Brad

---

<div class="post-metadata">

**Author:** ![bradcray](https://yyz2.discourse-cdn.com/free1/user_avatar/chapel.discourse.group/bradcray/32/72_2.png) [@bradcray](https://chapel.discourse.group/u/bradcray)\
**Post date:** [December 19, 2025, 2:06am UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/6 "2025-12-19T02:06:56Z")

</div>

PS — [Here's](https://ato.pxeger.com/run?1=hVJNagIxFIZCN57iw01nwI7UboriruteQITJTF6cQHyRJBpEepJu3LSH6mmacXRqF1ICSXh8fy95H191IzZkjsfPbVCPL99397VlpVdIhw9gzDGZDQa1Ed7jVQSBwwDYCYdqq9QUi6ei4BF-9yUcCZMowMbZGpp1yJQ2xGJNU_jgNK9yHPD-FyKT9k25Dp8YrfF6f8oxB1OEb4QjeUrWu8yHmtt7kTSH-QwYj2ETT-wrQqQHiSg4IFhsPaG0kUmWECzRiB0hNARljbExJU32ihxxTb4llJ15ibKorHM2ZnkJ5ewaOhSndJUT0p8DduD--d6spP755PQ6--zSXArRNdaCM9mL5EklOh3IcNZXLoXe86rGsqV00KL9q8VklNYyKT7_z-ym4TwUl-H4AQ) an executable example of the code sketched out above that demonstrates the aliasing by assigning to the original class and seeing the change reflected in the others:

---

<div class="post-metadata">

**Author:** ![jmag722](https://avatars.discourse-cdn.com/v4/letter/j/bbce88/32.png) [@jmag722](https://chapel.discourse.group/u/jmag722)\
**Post date:** [December 19, 2025, 12:30pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/7 "2025-12-19T12:30:53Z")

</div>

Hi Brad,

Sorry for the confusion. When I say, “has the same issue with copying”, it’s that the `Data` class would still need to handle copying/moving of the input array to initialize `buff` I think? I tried to make an example below. If we read from a file within the `Data` class we get around that though. But for a `Node` library it’d be hard to anticipate all the ways a user might want to load data in to initialize `buff`.

```chapel
class Data {
  // pretty sure I'd have to do this with the domain?
  var buffDom: domain = {1..0}; 
  var buff: [buffDom] real;

  proc init(ref buff: [?D] real, in copy: bool=false) {
    buffDom = D;
    if copy {
      this.buff = buff; // creates a deep copy?
    }
    else {
      // use swap to perform a move? might not be the best way, buff has to be filled first. ideally the formal argument would be left empty after
      this.buff = 0.0;
      this.buff <=> buff; 
    }
    
  }
}

var n = 100000000;
var dataBuff: [1..n] real = [...];
var myData = new shared Data(dataBuff);
var bradsData = myData;

class Node {
  var d: Data;
}

var nd = new Node(d = myData);

```

That’s good to know though that deep copies are not performed when passing `myData` to `bradsData` or `nd`.

Design-wise, I’m getting more unsatisfied with having a reference member field because it violates the encapsulation idea, could be a bit of a headache, all for the sake of avoiding a copy. Maybe providing the user a move and copy option would be better.

---

<div class="post-metadata">

**Author:** ![lydia](https://avatars.discourse-cdn.com/v4/letter/l/34f0e0/32.png) [@lydia](https://chapel.discourse.group/u/lydia)\
**Post date:** [December 19, 2025, 3:39pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/8 "2025-12-19T15:39:57Z")

</div>

> [@jmag722](#):
>
> Maybe providing the user a move and copy option would be better.

The good news is that we do have an option for that today, though I don’t know that it’s been as discussed as the `ref` field idea. It’s called [the MemMove library](https://chapel-lang.org/docs/modules/standard/MemMove.html), if I’m correctly understanding what you’re thinking of.

Lydia

---

<div class="post-metadata">

**Author:** ![jmag722](https://avatars.discourse-cdn.com/v4/letter/j/bbce88/32.png) [@jmag722](https://chapel.discourse.group/u/jmag722)\
**Post date:** [December 19, 2025, 10:49pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/9 "2025-12-19T22:49:41Z")

</div>

Hello Lydia, thank you this looks like a good way to provide that type of initialization

---

<div class="post-metadata">

**Author:** ![bradcray](https://yyz2.discourse-cdn.com/free1/user_avatar/chapel.discourse.group/bradcray/32/72_2.png) [@bradcray](https://chapel.discourse.group/u/bradcray)\
**Post date:** [December 20, 2025, 5:45pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/10 "2025-12-20T17:45:54Z")

</div>

[edited to fix dumb name mix-up on my part. Apparently I was awake enough to code but not to interact with humans; and then a second time to fix the broken ATO link]

Hi Jared —

Thanks for clarifying what you meant and apologies for the late response. I didn't get much time online yesterday.

I believe that what you want can be accomplished without using `MemMove`, though that's a good tool to keep in mind as well. Specifically, when arrays that are at the end of their lives are used to initialize other arrays, the memory from the initializing array can be used ("stolen") by the new array.

The keys to achieving this, IIRC, are (a) to use an `in` intent on the class initializer to indicate that it should get its own copy of the array rather than `ref`erring to an existing array and (b) making sure that the initializing array is obviously dead by making it a variable with fixed scope (i.e., not a module-level symbol) and ensuring there are no references to it after passing it into the `new` expression. Here's an example that demonstrates this, checking the address of the initial element of the array as a check that we're using the same array throughout [[ATO](https://ato.pxeger.com/run?1=fZO_TsMwEMYHtjwE-sRCAiVtmRBVJ5iZ2KqKuPGlNaR2ZbuNKtQnYWGBh-JpOCck_K-UxJL93f3uO-eeXvOFWFH5_Pyy9sXZxdvB4doRrm63K3KjKMqNLtQcvDgPjTHOw2YpnMO18AKPEbARFrN1UVxiMkxT3cPndwpLouQQYGVNDqWVj5WG5Nh_5UmdFfAL5dKQmLEhYMS7u2jX8m-MpI4vL-EWwpKsyxoFVQ1cCqXjpJMZq-bX-9iMmsSqd997SLhYPP5U7aZQJ8PBAKe45_ehPxykg1BYZZWnUsdHLQKl2pCD8DjqIb9beXtr4vZwMuR0_EyTpG5OqG25rcPG0FR9NRMH7-M2MhkB_T4bYWvbGaGiY4lKaA9vEK4uM5UmmUFoiYXYELeRUJiyNJXSczZZkCWdc2kckDXQDFk6M9aaKk4yFNYsoXz61VWjO3b1RZP901yjqW_sL38zK6T7sNhIv_WtO94P6WT_cth308Pwg8SyoyXfcFru52iZyt-IXdSMyce0tFPzDg)]:

```chapel
use CTypes;

config const n = 2;

class Data {
  var buff: [1..n, 1..n, 1..n] real;

  proc init(in data: [1..n, 1..n, 1..n] real) {
    this.buff = data;
  }
}

class Node {
  var d: shared Data;
}

proc main() {
  var origData: [1..n, 1..n, 1..n] real = [(i,j,k) in {1..n, 1..n, 1..n}] i*100 + j + k/10.0;
  writeln("origData lives at ", c_ptrTo(origData[1, 1, 1]));

  var myData = new shared Data(data=origData); // or maybe we'd want to use `owned` and have the following references to `myData` `.borrow()` from it.
  writeln("myData's buffer lives at ", c_ptrTo(myData.buff[1, 1, 1]));

  var bradsData = myData;
  writeln("bradsData's buffer lives at ", c_ptrTo(bradsData.buff[1, 1, 1]));

  var nd = new Node(d = myData);
  writeln("nd's buffer lives at ", c_ptrTo(nd.d.buff[1, 1, 1]));
}

```

I haven't tried a variation that uses different sized arrays for different instances of `Data`, but imagine that can be made to work without `MemMove` as well. I'll largely be offline the next few weeks but can wrestle with that more in the new year if it doesn't fall out easily/obviously.

-Brad

---

<div class="post-metadata">

**Author:** ![jmag722](https://avatars.discourse-cdn.com/v4/letter/j/bbce88/32.png) [@jmag722](https://chapel.discourse.group/u/jmag722)\
**Post date:** [December 23, 2025, 12:07pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/11 "2025-12-23T12:07:10Z")

</div>

This needs no immediate response, but wanted to acknowledge the reply. Happy holidays all

Thank you Brad,

That's good to know about how to get the copy elided, I think I'll go with that as it allows the user the choice without having to pass some `doCopy=true` to the constructor.

I do think there's still a use case for ref class members. Coming from doing data analysis at work, it'd be handy for pipelines where the data will outlive the operations performed on it. For instance, load data, create a handy class to operate on it or query it, once done throw that class object away, do something else with the same data, etc. Maybe that's a good case for functional programming over classes, or moving the data back out of the class once those operations are complete. But for more complex derived data structures a record or class with a ref member could be convenient

Best,

Jared

---

<div class="post-metadata">

**Author:** ![bradcray](https://yyz2.discourse-cdn.com/free1/user_avatar/chapel.discourse.group/bradcray/32/72_2.png) [@bradcray](https://chapel.discourse.group/u/bradcray)\
**Post date:** [January 5, 2026, 7:08pm UTC](https://chapel.discourse.group/t/ref-members-of-class-record/46782/12 "2026-01-05T19:08:53Z")

</div>

Glad it was helpful Jared!

> [@jmag722](#):
>
> I do think there's still a use case for ref class members

I completely agree—I find myself wanting the feature with some regularity, as do other users. I.e., none of this discussion negates my original, immediate reaction:

> [@bradcray](#):
>
> I'd really like `ref` fields in classes and records as well—of the language features that I'd consider to be "missing" today, I think it's priority #1 on my list.

Happy 2026!  
-Brad
