Subscripts
A subscript lets you call an instance like a function — container(key) — to index into it. It's how Array, Dictionary, and friends are wired up; you can wire your own types the same way.
struct Grid {
var width: Int
var cells: [Int] // row-major: cell (row, col) lives at row * width + col
subscript(row: Int, col: Int) -> Int {
get {
self.cells(row * self.width + col)
}
set {
self.cells(row * self.width + col) = newValue;
}
}
}
var g = Grid(width: 3, cells: [0, 0, 0, 0, 0, 0]);
g(1, 2) = 7;
let value = g(1, 2); // 7
A subscript declaration looks a lot like a computed variable: get and an optional set (with implicit newValue). Parameters follow the same labeling rules as functions — single-name parameters are positional (g(1, 2)); give a parameter two names to require a label at the call site.
Multiple subscripts
You can declare more than one — different label sets pick different subscripts, like overloaded functions:
<!-- sample: continue -->struct Point {
let x: Int
let y: Int
}
extend Grid {
subscript(at point: Point) -> Int {
get { self.cells(point.y * self.width + point.x) }
set { self.cells(point.y * self.width + point.x) = newValue; }
}
}
println("\(g(at: Point(x: 2, y: 1)))"); // same cell, different syntax
Read-only subscripts
Drop the set block to make the subscript read-only:
extend Grid {
subscript(rowSum row: Int) -> Int {
get {
var total = 0;
for col in 0..<self.width {
total = total + self.cells(row * self.width + col);
}
total
}
}
}
println("\(g(rowSum: 1))"); // 7
Assigning to a read-only subscript is a compile error.
Note: subscripts are called with parentheses (obj(key)), not square brackets — square brackets in Kestrel are reserved for type parameters.
Note: avoid assigning through chained subscripts (e.g. g.cells(row)(col) = v on a [[Int]] field) — nested subscript assignment is currently broken in 0.16 and slated for a fix in 0.17. Reads through chains are fine; for writes, keep the setter a single subscript deep, as the row-major Grid above does.