Array & ArrayView

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

“Make simple things simple”,
having a short and traditional syntax for dynamic arrays should encourage people to use it.

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).

“Make simple things simple”,
having a short syntax for associative arrays so they are easy to use.

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: