In Argentum all standard containers, return optionals (?T
) when indexed with x[i]
. Therefore, Argentum makes it impossible to access beyond the array bounds or using an invalid key in associative containers.
a = Array(String);
a.append("Hello");
a[0] ? log(_) // print the starting element of the array if it exists
log(a[0] : "") // print the starting element of the array, or an empty string
It not only helps to prevent OOB errors. It can drive business logic:
// Function gets an element from container and creates one if it's absent.
// It takes a container, a key, and a factory lambda:
fn getOrCreate(m MyMap, key int, factory()@Object) {
// If element exists, return it.
// Otherwise, call the lambda,
// store its result into the container under the key,
// and return it as its own result
m[key] : m[key] := factory()
}
Speaking of indexing operation: x[expressions]
is a syntactic sugar for calling the methods getAt | setAt. By defining such methods (with an arbitrary number of parameters of arbitrary types), you turn your class into a multi-dimensional containers.
Let's compare with other languages:
Java, C++ (with T::at), Swift, Go, Rust (with slice[index]) - perform runtime bounds checking and throw exceptions/panics. So resilience in these languages/scenarios require indexInBounds() ? container[index] :...
double checks.
Rust slice.get
returns optional, i.e. acts exactly as subscript in Argentum but with much heavier syntax:
// x = a[i] : 0;
let x = *a.get(i).unwrap_or(&0);
BTW. Iterators and forEach
can reduce the number of subscripts but can't replace them entirely.