2

In the following code, I'm trying to get the 1st and 2nd rows of array A by using either var or ref. Here, my understanding is that var always creates a new array, while ref creates an alias (or reference) to the right-hand side.

var A: [1..2, 1..3] int;
A = 0;

var row1 = A[ 1, .. ];
ref row2 = A[ 2, .. ];

row1 = 10;
row2 = 20;

writeln( "row1 = ", row1 );
writeln( "row2 = ", row2 );

writeln( "A = ", A );

The result is as expected (i.e., the 1st row of A is not modified):

row1 = 10 10 10
row2 = 20 20 20
A = 0 0 0
20 20 20

But if I print the type of row1 and row2

writeln( "row1.type = ", row1.type: string );
writeln( "row2.type = ", row2.type: string );

I get this result:

row1.type = [ArrayViewRankChangeDom(1,int(64),false,2*bool,2*int(64),ArrayViewRankChangeDist(DefaultDist,2*bool,2*int(64)))] int(64)
row2.type = [ArrayViewRankChangeDom(1,int(64),false,2*bool,2*int(64),ArrayViewRankChangeDist(DefaultDist,2*bool,2*int(64)))] int(64)

This is somewhat surprising because I assumed row1 to be a "usual" array (i.e., not an alias). For example, the following vec (which I call a "usual" array)

var vec: [1..3] int;
writeln( "vec.type = ", vec.type: string ); 

gives

vec.type = [domain(1,int(64),false)] int(64)

So I'm wondering whether there is some difference between row1 and vec (as array types)...?

roygvib
  • 7,218
  • 2
  • 19
  • 36

1 Answers1

2

I'm wondering whether there is some difference between row1 and vec (as array types)...?

There is a difference, though whether or not you consider it a difference in type will depend somewhat on what your notion of type is. Every Chapel array is defined in terms of a domain map which specifies how it is defined (and how its domain is defined). If no domain map is specified, a default domain map is used. An array's domain map is technically part of its type, though in practice, it tends to be an aspect that should impact how the array is implemented more than the operations that can be applied to the array.

So vec in your example is a 1D array of int(64) elements indexed by int(64)s (and its indices are non-stridable which is what the false in its domain's signature represents), and its domain map is the default domain map. Meanwhile your slice expressions A[i, ..] are also 1D arrays of int(64) elements indexed by int(64)s (and are also non-stridable), yet their domain maps are ArrayViewRankChange. This is an internal domain map which represents a rank-change alias ("view") of another array.

[The short version of the rationale for using this distinct domain map to represent the rank-change slice of the array is this: if the original 2D array is distributed (say), a 1D slice of it should presumably be similarly distributed as well -- this suggests that it shouldn't be a default domain map (which is not distributed) nor the original array's distribution (which describes how to implement 2D things). So the choice is either to have rank-change slices require domain maps to create new lower-dimensional domain maps of themselves (which tends to be somewhere between challenging and impossible) or to use a new domain map that knows how to translate from 1D indices to the original distribution's 2D indices. This is what the ArrayViewRankChange domain map does. A longer version of the rationale can be found in the 1.15 release notes starting on slide 27 ("Array Views").]

Given the above, it probably makes sense that row2 would also indicate ArrayViewRankChange as its domain map since it is a reference to a rank-change slice expression. But it may be more surprising that row1 would, since it is a brand-new array resulting in a deep copy of the ArrayViewRankChange array and could therefore use traditional default array storage. But the rationale can again be seen in the distributed case where that new array variable should (presumably) have the same distribution as the original---and our means of doing so is via the ArrayViewRankChange.

If you wanted to force an array slice to be "a normal array", you could do so using a more precise declaration:

var row1b: [A.domain.dim(2)] A.eltType = A[1, ..];

At which point its type will match vecs:

row1b.type = [domain(1,int(64),false)] int(64)

All that said, hopefully you will find that you can use row1 and row2 in most places that you could use vec. If not, please ask a follow-up question or file an issue on GitHub.

As a closing note, arguably the compiler could/should do a better job of printing array types more cleanly, or at least to offer different options for the level of verbosity in printing out its type (e.g., in many cases, perhaps identifying the domain map is unnecessary, or perhaps the domain type could be printed out more simply?)

Brad
  • 3,839
  • 7
  • 25