Kontextbezogene und ausgelassene Ausdrücke

Kontextbezogene Ausdrücke sind Ausdrücke, die nur in bestimmten Kontexten gültig sind. Ein Beispiel wäre etwa die Verwendung von Elementnamen in Copy-and-Update-Ausdrücken, ohne sie qualifizieren zu müssen.

Ausdrücke können weggelassen werden, wenn sie vom Compiler abgeleitet und automatisch eingefügt werden können, wie dies beispielsweise bei Anweisungen zur Auswertung und Neuzuweisung der Fall ist.

Bereiche mit offenem Ende sind ein weiteres Beispiel, das sowohl für kontextbezogene als auch für ausgelassene Ausdrücke gilt. Sie sind nur in einem bestimmten Kontext gültig, und der Compiler übersetzt sie während der Kompilierung in normale Range-Ausdrücke, indem er geeignete Grenzen ableitet.

Ein Wert vom Typ Range generiert eine Sequenz von ganzen Zahlen, die durch einen Startwert, einen (optionalen) Schrittwert und einen Endwert angegeben wird. Der Range-Literalausdruck 1..3 generiert beispielsweise die Sequenz „1,2,3“. Analog dazu generiert der Ausdruck 3..-1..1 die Sequenz „3,2,1“. Bereiche können auch verwendet werden, um auf der Grundlage eines bereits vorhandenen Arrays mittels Aufteilung ein neues Array zu erstellen. Beispiel:

    let arr = [1,2,3,4];
    let slice1 = arr[1..2..4];  // contains [2,4] 
    let slice2 = arr[2..-1..0]; // contains [3,2,1]

In Q# können keine unendlichen Bereiche definiert werden. Anfangs- und Endwert müssen immer angegeben werden. Einzige Ausnahme ist die Verwendung von Range, um ein Array aufzuteilen. In diesem Fall kann der Start- oder Endwert des Bereichs vom Compiler abgeleitet werden.

In den obigen Beispielen zur Aufteilung eines Arrays kann der Compiler davon ausgehen, dass das beabsichtigte Bereichsende der Index des letzten Elements im Array ist, wenn die Schrittgröße positiv ist. Ist die Schrittgröße negativ, soll das Bereichsende wahrscheinlich der Index des ersten Elements im Array sein (also 0). Das Umgekehrte gilt für den Beginn des Bereichs.

Zusammenfassend lässt sich sagen, dass, wenn der Startwert des Bereichs weggelassen wird, der abgeleitete Startwert

  • Null ist, wenn kein Schritt angegeben wird oder der angegebene Schritt positiv ist.
  • die Länge des Arrays minus 1 ist, wenn der angegebene Schritt negativ ist.

Wenn der Bereichsendwert weggelassen wird, dann ist der abgeleitete Endwert

  • die Länge des Arrays minus 1, wenn kein Schritt angegeben wird oder der angegebene Schritt positiv ist.
  • Null, wenn der angegebene Schritt negativ ist.

Q# lässt somit die Verwendung von Bereichen mit offenem Ende innerhalb von Ausdrücken zur Aufteilung eines Arrays zu. Beispiel:

let arr = [1,2,3,4,5,6];
let slice1  = arr[3...];      // slice1 is [4,5,6];
let slice2  = arr[0..2...];   // slice2 is [1,3,5];
let slice3  = arr[...2];      // slice3 is [1,2,3];
let slice4  = arr[...2..3];   // slice4 is [1,3];
let slice5  = arr[...2...];   // slice5 is [1,3,5];
let slice7  = arr[4..-2...];  // slice7 is [5,3,1];
let slice8  = arr[...-1..3];  // slice8 is [6,5,4];
let slice9  = arr[...-1...];  // slice9 is [6,5,4,3,2,1];
let slice10 = arr[...];       // slice10 is [1,2,3,4,5,6];

Da die Bestimmung, ob der Bereichsschritt positiv oder negativ ist, zur Laufzeit erfolgt, fügt der Compiler einen geeigneten Ausdruck ein, der zur Laufzeit ausgewertet wird. Für ausgelassene Endwerte lautet der eingefügte Ausdruck step < 0 ? 0 | Length(arr)-1, und für ausgelassene Startwerte lautet er step < 0 ? Length(arr)-1 | 0, wobei step der für den Bereichsschritt angegebene Ausdruck ist, oder 1, wenn kein Schritt angegeben ist.