Osy#betaRun it on Osyrin: osyrin.com

Reference / Function

Index from end and ranges

xs[^1] · s[1..3] · s[2..] · arr[..2] · s[^3..]

C#'s index from the end (^n) and ranges (a..b) inside an indexer. ^1 is the last element of a string, an array or a list; a range slices a string into a substring and an array into a new array, end exclusive.

stable1 example compiled by CIfunctioncollectionstring

Summary#

^n is the position n elements before the end, so xs[^1] is the last element — on a string, an array and a list. a..b is the range from a up to (not including) b; either end may be left out, and either may be written from the end: s[1..3], s[2..], arr[..2], s[^3..]. A string's range is a substring, an array's is a new array.

Signature#

xs[^<int n>]                 // the element n before the end — xs[xs.Length - n] (Count on a list)
s[<start>..<end>]            // string → string, end exclusive; either bound may be ^n or omitted
arr[<start>..<end>]          // T[] → a new T[]

Description#

  • The same answers as C#. ^1 is the last element and ^0 is one past it (reading it faults, as in C#). s[a..b] is s.Substring(a, b - a) — an out-of-range bound faults the way Substring does.
  • Where they are read. Inside an indexer. C# also lets ^1 and 1..3 be stored as Index/Range values; Osy# has no such value, so outside [ ] they are refused by name with the indexer to write instead.
  • A list takes ^n but not a range — as in C#, List<T> has no range indexer; copy a slice with xs.GetRange(start, count).
  • The value is read once per use. The indexed value and each bound must be something that can be read again — a variable, a field, a literal — because the lowering reads the length and then the element. Anything else (a call) is refused with the fix: bind it to a local first.
  • Precedence is C#'s: .. binds tighter than arithmetic, so a computed bound is parenthesised — s[1..(n - 1)].

Examples#

string Last(string s) => $"{s[^1]}";                        // "o" for "hello"
string Middle(string s) => s[1..^1];                        // "ell"
int[] Head(int[] xs) => xs[..2];                            // { 1, 2 } of { 1, 2, 3 }
int LastOf(List<int> xs) => xs[^1];

See also#

Related

List indexer

Positional get/set on a List<T> by integer index, exactly like C#'s List<T>.this[int]. The index must be an integer…

Array literals

An array literal [a, b, c] is a value: a list you can return, assign, pass as an argument, or supply as a UI prop. Its…