Array & ArrayView

“Make simple things simple”,
having a short and traditional syntax not only for static, but also for dynamic and associative arrays should encourage people to use it.

Dynamic Array

Int[] dynamicArrayOfIntegers is an array with dynamic size.

Int[] array = [0, 1, 2]
array[0] = 0
array[1] = 0
array[2] = 0
array[3] = 0  // Runtime error, no compile time bounds check

T[] arr is the short form of cilia::Array<T> arr.

The long form is called Array<T>, not Vector<T>, because

“Raw” C/C++ arrays are handled with T* instead.
std::array is called cilia::StaticArray instead.

In C/C++ T[] means “array of certain (inferred) size”,

Static Array

Int[3] arrayOfThreeIntegers is an array with fixed size (instead of Int arrayOfThreeIntegers[3] in C/C++).

Int[3] array = [0, 1, 2]
array[0] = 0
array[1] = 0
array[2] = 0
array[3] = 0  // Compilation error, due to compile time bounds check

arrayOfThreeIntegers.size() -> 3
is realized as extension function

extension<type T, Int N> T[N] {
    func size() -> Int { return N }
}

Use T+/UniquePtr<T> for “raw” C/C++ arrays of arbitrary size.
But array subscript with Int+ is unsafe.

Int[0]+ array = new Int[3]
unsafe {
    array[0] = 0
    array[1] = 0
    array[2] = 0
    array[3] = 0  // Undefined behaviour, no bounds check at all
}

Using Int* for arrays is possible but generally unsafe.

Int[0]+ uniquePtrToArray = new Int[3]
unsafe {
    Int* array = move(uniquePtrToArray)
    array[0] = 0
    array[1] = 0
    array[2] = 0
    array[3] = 0    // Undefined behaviour, no bounds check at all
    delete[] array  // Array-delete!
}
unsafe {
    Int* array = reinterpretCastTo<Int*>(malloc(3 * sizeof(Int)))
    array[0] = 0
    array[1] = 0
    array[2] = 0
    array[3] = 0  // Undefined behaviour, no bounds check at all
    free(array)
}

Actually this is how to handle pointer to array of Int “properly”:

Int[3]+ arrayPtr = new Int[3]
(*arrayPtr)[0] = 0
(*arrayPtr)[1] = 0
(*arrayPtr)[2] = 0
(*arrayPtr)[3] = 0  // Compilation error, due to compile time bounds check

But raw pointer access is still unsafe:

unsafe {
    Int[3]* arrayPtr = new Int[3]
    (*arrayPtr)[0] = 0
    (*arrayPtr)[1] = 0
    (*arrayPtr)[2] = 0
    (*arrayPtr)[3] = 0  // Compilation error, due to compile time bounds check
    delete[] arrayPtr   // Array-delete!
}

Examples

ArrayView

AKA Slice AKA Subarray.

Incomplete ranges (need lower and/or upper bounds before use) are typically implemented as inline functions that determine the concrete bounds and then call array[start..end] (or one of the exclusive counterparts).

See Rust Slices

Multidimensional Array

Associative Array

AKA Map (or Dictionary).
TValue[TKey] as short form of Map<TKey, TValue> (as in D).

There is no difference between these two forms, but the long form is necessary for other map variants (SortedMap, HashMap, etc.).

Example:

ContactInfo[String] contactInfoForID
// as short form of  
Map<String, ContactInfo> contactInfoForID

Maybe partial template specialization: