Static-Sized Arrays
This is a new proposed syntax for handling array types whose size is fixed at 
compile time. This is a classic kind of type that's still missing in Swift.

Like the built-in processor numeric types are mapped to special struct types, 
any built-in vector types should be mapped to special array types. There should 
be some sort of construct to allow parallel visitation of elements.

For a given array type A with an element type B, we have strideof(A) == COUNT * 
strideof(B), where COUNT is the number of elements in the array, which is the 
product of the lengths along each dimension. (A zero-dimension array has an 
element count of one.)

New Keywords
array
of
These keywords should be conditional if possible. The of shouldn't appear 
without following an array, so of should be easy to make conditional.

Immediate Arrays
Immediate arrays are a new kind of compound type. They have value semantics.

let x: array 3 of Int = [1, 2, 3]
var y: array 2 of array 5 of Double
Hopefully, this is simpler than my last proposal. I'm thinking that "array" is 
like a verb here.

The element type is at the end, so no parentheses (or similar) are needed. The 
syntax is easy to expand for nested array types. Here, the extents go from the 
widest span to the narrowest, like nested arrays in C. The inner element type 
is at the end instead of the start.

assert(x.0 == 1)
x.3 = 3  // ERROR!
y.1.3 = 3
y.0 = [-3, -2, -1, 0, +1]
Elements are addressed just like in tuples.

Nominal Arrays
Nominal arrays are a new kind of named type. They have value semantics.

array MyArray: (0..<6) of Int {
    /* ... */
}
I'm thinking "array" is like an adjective (or noun) here. The base-and-protocol 
list must have a shape specifier as its first item.

shape-specifier → ( extents-list_opt ) of type

extents-list → extent

extents-list → extent , extents-list

extent → type storage-rank_opt

extent → expression ..< expression storage-rank_opt

extent → expression ... expression storage-rank_opt

storage-rank → : expression
A type used for an extent:

Must be a raw-value enumeration type.
The raw-value type must be one of the default integer types.
There must be at least one case, and all the cases must form a contiguous range 
of values.
A range used for an extent:

Must use for its boundary type either:
a default integer type, or
an enumeration type that could qualify as an extent type.
Must be a valid range with at least one element.
The expression for a storage rank must evaluate to a compile-time integer value 
that is at least zero and less than the number of extents. An extent without an 
explicit storage rank gets one equal to the smallest valid value yet unused. 
(Multiple extents without explicit ranks are finalized in lexical order.)

The extent with the largest storage rank has elements with adjacent indexes 
(assuming all other extents use fixed indexes) placed adjacent in memory. The 
extent with storage rank 0 have elements with adjacent indexes (assuming all 
other extents use fixed indexes) the furthest span apart in memory.

The total number of elements for the array is the product of the lengths of the 
extents. A zero-dimension array has a singular element.

A nominal array type can have type-level members and computed instance-level 
properties, just like the other named types. The initial set of members, if not 
overridden, are:

A type-alias Element that refers to the element type.
A type-alias Index that refers to a tuple composed of the extent types. For a 
range-based extent, the corresponding type is its boundary type.
If the element type is default-initializable, a default initializer.
An initializer that takes as its only parameter an Element, which is copied to 
each element.
An initializer that takes as its only parameter a closure that takes as its 
only parameter an Index and returns the value the corresponding element starts 
with.
An initializer similar to the previous, but the closure takes the index tuple's 
parameters separately.
Two subscript members, with get and set modes, to handle dereferencing. One 
member takes an Index, the other an exploded index list. It's an error to refer 
to an invalid index location.
Flexible Array Reference
To not have to fix a function for each extent shape, something similar to the 
old T[] array segment idea from C(++) is needed:

func foo(x: array of Int) -> Int
func bar(y: array of mutating Double) -> Int
Without a size given inside the array declaration, these functions can work 
with any array with the given element type. Array-segment references are 
reference types.

An array-segment reference conforms to RandomAccessCollection. A reference that 
is marked mutating also conforms to MutableCollection. (Should we create a new 
mutable keyword instead?)

A function that returns or otherwise writes out an array-segment reference must 
ensure it points to memory that will survive the function's end. (I'm not sure 
we should enforce some sort of retain/ARC instead.) (Should we ban these 
instead?)

An array-segment reference can be generated from an immediate array or a 
nominal array using as. A reference can be mutatingif the source array starts 
in var mode. Array-segment references access their elements in storage order.

Conversions
These conversions can work through as:

array N of T → array of T
array N of T → array of mutating T, if the source array was in var mode
array N of T → array M * N of U, when T is an array M of U
MyArray → array of MyArray.Element
MyArray → array of mutating MyArray.Element, if the source array was in var 
mode.
array of mutating T → array of T
array of T → array of U, where U is the element type of T
array of mutating T → array of mutating U, where U is the element type of T
Any conversion that requires a chain of these is also legal. When a function 
has an array-segment reference as a parameter, and the argument is an array 
with the same element type, the argument doesn't need an explicit as.

(Should we allow the reverse-direction transformations, or even chains of them, 
with "as!" and/or "as?"? Note that this could end up converting an array 5 of 
Int to an array 3 of array 2 of Int with its last Int nested element invalid.)

Parallel/Vector Processing (only semi-serious)
As the processor's built-in numeric types are mapped to the default numeric 
types, we should do something similar for a processor's built-in vector numeric 
types. Like a processor that has four integers as a vector, we could define a 
Int_4 structure type that maps to it.

We also need a way to possibly do evaluations in parallel. What about:

do x, y, z as array {
    z = x == y
    x += y
}
The three objects between do and as have to have the same shape. Within the 
block, the object names now refer to corresponding individual elements.

Extra Traits
As I was writing this, I came up with new functionality and corresponding 
keywords. Should we have an #extentsof(type)to use an extent shape from one 
nominal array type to another? Should we have an #extentscount(type)?

Example: take the do as array block. If x and y were function parameters, but z 
was an internal object, how would we define z besides manually copying the 
shape list?

— 
Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com 

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to