An indexer expression consists of a pair of square brackets (
) containing one or more expressions, separated by comma. The number and type of the expressions depends on the definition of the indexed expression.
var x := lMyArray[5, 8]; var y := lDictionary['Foo']; var z := lMyTuple;
Arrays can have one or more dimension, and when indexing the array as many indexer expressions can be provided as there are dimensions. If the number of indexes matches the number of dimension, an array element is the result; if fewer expressions are provided, the result is a sub-array with the remaining dimension(s).
var a := array [0..9, 0..9] of String. This can be thought of as a square of 100 string values, or ten rows with ten columns each.
Indexing the array with two indexer expressions accesses one specific string.
a[0,0] is the very first string, and
a[9,9] the very last.
a[0,9] is the last string oin the first column, while
a[9,0] is the first string of the last column.
(which index represents the "column" and which one the "row" is completely arbitrary, of course, and depends on the semantics behind the actual data in the array).
Indexing the array with a single expression will return a subarray, one individual row of the array.
a ios the first row (an
array [0..9] of String, itself), while
a is the last row.
Of course, sub-arrays can be indexed themsleves, so
a will index the first row, and then index the last element in it, essentially being equivalent to
var a := array [0..9, 0..9] of String; var first := a[0, 0]; var last := a[9, 9]; var x := a[0, 9]; var y := a[9, 0]; var sub := a; // sub is an array[0..9] iof String last z := sub; // same as a[0,9]
Arrays are always indexed with an Integer, Enum or Boolean type, depending on how the array was defined. Each dimension of an array can start at
0 (the default), or at an arbitrary start value specified when declaring the array, and must fit within the bounds of the array.
Indexed Properties are a special kind of properties, that look similar to an array, when being used, but under the hood provide their own code to access and store individual items.
Like Arrays, indexer properties can define one or more parameter, or dimensions, but unlike arrays, these parameters can be of any type, including non-numeric ones. Also unlike arrays, accessing an indexed property always requires all parameters, one cannot obtain a "slice" of a multi-dimensional indexed property.
property Languages[aName: String]: String; ... ... var x := Languages['Swift'];
Essentially this is just a convenient shortcut to omit the name of the property but it allows for cleaner and richer APIs, especially for objects where the indexed data is their main purpose (such as a List or a Dictionary class, for example:
var lNames := new List<String>; ... var y := lNames.Count; var x := lNames; var z := lNames.Items; // more verbose and less intuitive
Individual members of a Tuple can also be accessed via an indexer expression. Tuples are always indexed with an constant integer expression, starting at zero and ending one value below the number of items in the tuple. The result is strognly typed to the particular member of the tuple.
var t := (1, 'Hello', true); var a := t; // a is an Integer var b := t; // b is a String var c := t; // c is a Boolean var d := t[a]; // 🛑 Compiler error - tuple index must be constant
Writing to Indexer Expressions
Assuming the underlying expression is not read-only, indexers can be assigned to, to change an individual value of the expression.
a[5,5] := 'Center(ish)'; p['Oxygene'] := 'My favorite propgramming language'; t := 5;