Generics in Chapel
Chapel supports generic programming through its concept of “where clauses” and type parameters. Let’s explore how to implement generic functions and types in Chapel.
First, let’s create a generic function similar to the SlicesIndex
function:
proc slicesIndex(arr, v) where arr: [] ?eltType, v: eltType {
for i in arr.domain {
if arr[i] == v {
return i;
}
}
return -1;
}
This function takes an array arr
and a value v
, and returns the index of the first occurrence of v
in arr
, or -1 if not present. The where
clause specifies that arr
must be an array of some type eltType
, and v
must be of the same type.
Now, let’s create a generic linked list type:
class List {
type eltType;
var head, tail: unmanaged Node(eltType)?;
proc push(v: eltType) {
var newNode = new unmanaged Node(eltType, v);
if tail == nil {
head = tail = newNode;
} else {
tail!.next = newNode;
tail = newNode;
}
}
iter these(): eltType {
var current = head;
while current != nil {
yield current!.val;
current = current!.next;
}
}
}
class Node {
type eltType;
var val: eltType;
var next: unmanaged Node(eltType)?;
proc init(type eltType, val: eltType) {
this.eltType = eltType;
this.val = val;
}
}
In this implementation, List
is a generic class that can hold elements of any type. The push
method adds elements to the list, and the these
iterator allows for easy iteration over the list elements.
Now let’s use these generic constructs:
proc main() {
var s = ["foo", "bar", "zoo"];
writeln("index of zoo: ", slicesIndex(s, "zoo"));
var lst = new List(int);
lst.push(10);
lst.push(13);
lst.push(23);
write("list: ");
for elem in lst {
write(elem, " ");
}
writeln();
delete lst;
}
In this main
function, we first demonstrate the use of the slicesIndex
function with an array of strings. Then, we create a List
of integers, push some values onto it, and iterate over its elements.
To run this program, save it to a file (e.g., generics.chpl
) and use the Chapel compiler:
$ chpl generics.chpl -o generics
$ ./generics
index of zoo: 2
list: 10 13 23
Chapel’s approach to generics allows for type-safe, reusable code. The where
clauses and type parameters provide a powerful way to express constraints and create generic functions and types.