When is it advantageous to use Record
type vs a Class in Chapel? On IRC someone mentioned that Records distribute over locales better or something.
Records and classes are similar in Chapel in that they both support the creation of objects with fields and methods. That said, there are some major differences as well . Here's a quick review of some of those differences (tl;dr: records are roughly like C structs while classes support class hierarchies, dynamic dispatch, etc.), followed by a summary that gives some indications as to when you might choose to use one or the other:
Put another way, a record variable is the record object, such that there is no distinguishing between the two. In contrast, a class variable points to a class object which may be stored on a different locale from the variable itself (i.e., class variables can refer to objects stored across distributed memories).
An implication of this is that when one record is assigned to another, the value of the RHS record is copied to the LHS record's value (e.g., typically the fields of the RHS record are copied to the fields of the LHS record). Another implication is that records have to define (or use the compiler-provided) copy initializers, and often provide 0-argument initializers to establish new record objects.
In contrast, when one class is assigned to another it makes the LHS class variable refer (point) to the same object as the RHS class variable. In addition, because class variables are pointers, they have the option of storing the nil
value as a sentinel (though Chapel also supports non-nilable class variables that avoid the need for runtime checks or the risk of nil-pointer dereferences).
This means that the lifetime of a class object can be independent of the program's structure, where it relies on one of several policies to manage its memory (owned
, shared
, borrowed
, unmanaged
). In contrast, record objects can be thought of as always being automatically memory managed, yet constrained by lexical scoping.
As a specific example, if you have an array of classes, you've typically created a contiguous sequence of pointers that may refer to objects living anywhere on the system (the local heap or some other locale's heap). Whereas if you have an array of records, its storage will typically be a contiguous sequence of record objects.
An implication of this is that if you want to create a "pointer-based" data structure in Chapel—like a linked list, tree, or graph—you will typically use class objects to store the nodes of that data structure with fields of class type to refer to their neighbors (whereas it would be challenging to represent these nodes using records since Chapel has no pointers and they're allocated in-place; put another way, a Chapel record cannot contain fields of its own type because it would effectively result in an infinitely recursive data structure).
This means that if you want to create an object hierarchy as in Java or C++, you'll want to use classes, and that initializers for such class hierarchies are themselves hierarchical.
Given these distinctions, you'll typically want to use a class if:
You'll typically want to use a record if:
owned
classes can have this effect as well)In practice, combining the two can be quite powerful. For example, a record with a class field can be used to create a reference-counted object by having the class implement the object's identity and the record implement the reference counting semantics via assignment overloads and copy initializers to deal with the cases when copies of the record enter and leave scope, are assigned, etc. (however, note that shared
classes in Chapel provide this capability directly, so this is just an illustration not a common practice).