There have been proposals about that, revolving around creating a new tuple 
syntax for fixed-size arrays, like (Int x 5), and adding a subscript to them. 
IIRC, the sentiment was largely positive but people couldn't agree on the 
specific syntax.

I pushed a little bit for CollectionType on these, regardless of the type 
syntax (could have been (Int, Int, Int, Int, Int) for all I was concerned), but 
there were apparently important implementation challenges stemming from tuples 
being non-nominal types.

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/009682.html
 
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/009682.html>

I would like to revive this discussion, but I'm afraid that we're getting late 
for the Swift 3 release.

Félix

> Le 25 juin 2016 à 22:13:43, Daryle Walker via swift-evolution 
> <[email protected]> a écrit :
> 
> [I’ve seen the WWDC 2016 Keynote and State of the Platforms videos.  I 
> haven’t seen any others so I don’t spoil myself before typing my ideas down.  
> Apologies if this has already been covered.]
> 
> Is there any problem to adding fixed-sized arrays?  From what I glanced here, 
> it’s more like no one has gotten around to it and less like the very idea is 
> hated.
> 
> Obviously, the main advantages are that object storage (or pointer storage 
> for reference types) is on the stack and that the shape (i.e. the number of 
> extents and range for each extent) is fixed at compile time.  This type of, 
> well, type can be used when the baggage of length changing isn’t needed  Such 
> arrays are also a classic type since we started system-programming languages. 
>  (I was surprised by their absence in Swift when I first read the books.)  
> They can be mapped to a vector processing unit’s built-ins.
> 
> This:
> 
>> struct ArrayOf5<T> {
>> 
>>     let count = 5
>> 
>>     var first: T
>>     var second: T
>>     var third: T
>>     var fourth: T
>>     var fifth: T
>> 
>>     init(array: [T]) {
>>         first = array[0]
>>         second = array[1]
>>         third = array[2]
>>         fourth = array[3]
>>         fifth = array[4]
>>     }
>> 
>>     subscript(index: Int) -> T {
>>         get {
>>             var preResult: T?
>>             switch index {
>>             case 0:
>>                 preResult = first
>>             case 1:
>>                 preResult = second
>>             case 2:
>>                 preResult = third
>>             case 3:
>>                 preResult = fourth
>>             case 4:
>>                 preResult = fifth
>>             default:
>>                 preResult = nil
>>             }
>>             return preResult!
>>         }
>> 
>>         set {
>>             func doAssign(destination: UnsafeMutablePointer<T>) {
>>                 destination.memory = newValue
>>             }
>> 
>>             switch index {
>>             case 0:
>>                 doAssign(&first)
>>             case 1:
>>                 doAssign(&second)
>>             case 2:
>>                 doAssign(&third)
>>             case 3:
>>                 doAssign(&fourth)
>>             case 4:
>>                 doAssign(&fifth)
>>             default:
>>                 doAssign(nil)
>>             }
>>         }
>>     }
>> 
>> }
> 
> 
> shouldn’t be better supported than directly having built-in fixed-sized 
> arrays.  (I’ve wondered if we should have a library or built-in arrays.  I’ve 
> decided that even if we add a library, we still need the built-in.)  Although 
> I parametrized the type, altering the shape (right now 1 dimension of 5 
> elements) doesn’t scale since it requires lexical change.  Internally, a 
> built-in array type would be something like this, modulo optimizations and 
> not having to come up with names for each element.
> 
> —————
> 
> [The following sections are my ideas about implementation; we don’t have to 
> use them.]
> 
> What should array type expressions look like in code?
> 
> Since generics (currently) only use type-based parameters, we can’t do 
> something C++-ish like “array<T, 1, 4, 3>”.  I did have a thought of 
> “[MyType; 5]”, but that seemed too close to current arrays.  I was shocked to 
> discover that Rust uses that syntax.  However, it’s still to bad to use now 
> because ‘[MyType]” would mean something different that it does currently 
> (zero-dimensional array of a single unit instead of one-dimensional array of 
> arbitrary number of elements).
> 
> Since arrays are product types (I think), let’s use multiplication syntax:
> 
>> var myArray: MyType * [6]  // This is an array of six elements, each of 
>> `MyType`
>> var myArray2: MyType * [6] * [5]  // This is an array of five elements, each 
>> a six-element array of `MyType`
>> var myArray3: MyType * [3, 4]  // This is an array of three-by-four, each 
>> element of `MyType`
> 
> The “[ SHAPE ]” syntax affects the type expression to its left.  An empty 
> list is not allowed since, although array-literal syntax allows empty lists, 
> the subscript operation does not.  Note, to keep the syntax regular, the 
> first subscript when using “myArray2” is for five elements, i.e. “0..<5”, and 
> the second (if any) is for six, the reverse lexical order of declaration.  
> This is because we don’t have C’s cute “declaration equals usage” type 
> syntax.  Also note that “myArray3” requires a single subscript call with two 
> coordinates in it to dereference.  Supplying only one coordinate is 
> nonsensical.  (“myArray2” is the other way when you want to dereference a 
> “MyType” value.)
> 
> Of course, not using a shape expression gives you a zero-dimensional array 
> (i.e. a regular variable) of your base type by default.  (So, it would 
> actually be "0 + extents(MyType.self)" dimensions.)
> 
> Or we could just do it the same way C does it (i.e. “MyType[8]”), and 
> preserve nested arrays having the same lexical order in declaration and 
> dereference.  We could even forbid multi-dimensional arrays and just do 
> nested single-dimensional arrays like C (and move multi-dimensionality to 
> wrapper structs), but I feel that would be giving up on improving the 
> abstraction.
> 
> ——
> 
> What about row vs. column order?
> 
> If you stick with chaining one-dimensional arrays, you get only row-order, 
> just like C (which can only do nested one-dimensional arrays).  If you use a 
> multi-extent shape expression, you can override the order:
> 
>> var myArray1: MyType * [3, 4] * #rank[0, 1]  // Default; row-order
>> var myArray2: MyType * [3, 4] * #rank[1, 0]  // Reversed; column-order
>> var myArray3: MyType * [3, 4, 5] * #rank[0, 2, 1]  // Scrambled
> 
> The array literal attached to the rank command has to contain every value in 
> 0..<count exactly once.  The position of the “0” value is the spacing with 
> the longest span, “count - 1” is the adjacent elements level.
> 
> A rank command can only appear directly after a shape expression or an 
> element type expression, and not after another rank command.  The command’s 
> literal must have the same length as the number of extents of the 
> corresponding shape expression.  A rank command following an element type 
> expression, whether it’s a non-static-array type or a static-array type 
> hidden behind a type alias, is treated as a zero-dimensional array so 
> “#rank[]” is the only legal rank command for them.
> 
> The rank command does not pierce type aliases; “#rank[]” is the only valid 
> command for them.  The alias itself can have a rank command, which affects 
> all objects declared with that alias, and cannot be overridden.  (If the 
> alias doesn’t have a rank command, the index storage priority is fixed to the 
> default.)  Should a rank-stripping command be added?  Should an rank command 
> that pierces aliases and/or overrides previous ranks be added?
> 
> Types that differ in number of shape commands, number of extents within 
> corresponding commands, size of corresponding extents, index storage 
> priorities, or element type are different types.  We should have a function 
> that can reshape an array if the total number of the outermost 
> non-static-array objects are the same.  (The function could reshape a 
> non-static-array type to a static array of one element with any nesting.)
> 
> (If we give up on improving the abstraction compared to C, this rank order 
> would be simulated in a wrapper struct that rearranges the indices.)
> 
> ——
> 
> What about initialization?
> 
> I didn’t use initialization expressions before because it’s hard.  We’ll have 
> to work on this.
> 
> Zero-dimensional arrays (i.e. a regular non-static-array type) are 
> iniitalized as usual.
> 
> A one-dimensional static-array gets initialized like a current dynamic array. 
>  But the syntax given below will also be accepted (with just one coordinate, 
> of course).
> 
> For higher-dimensional arrays, we need something like:
> 
>> [(0, 0, 0): myFirstValue, (2, 4, 1): mySecondValue, …]
>> [(0, 0): myFirstValue, (0, 1): mySecondValue, default: myDefaultValue]
> 
> and/or:
> 
>> var myArray: MyType * [3, 4] = { return 2 * $0 + 7 * $1 }
> 
> (We can use “myParam1, myParam2 in” syntax for that last one too.)  Can/could 
> we have an array expression that is part (XX, YY) and part $0/$etc formula?  
> Maybe with “_” and/or “case” and/or “where” to differentiate which elements 
> get the $0/$etc and which ones get a “default:” phrase?  Maybe the 
> _/case/where could be used within incomplete (XX, YY)-style indexing?
> 
> ——
> 
> Should there be flexible-ending arrays?  Other value types?
> 
> Let’s say that at most one extent in a shape expression can be “any” instead 
> of a compile-time integer expression.  Let’s restrict the “any” dimension to 
> be the rank-0 one, using “#rank” to override if you didn’t put the “any” 
> first.  Let’s call these flexible-ending static-arrays.
> 
> Flexible-ending static-arrays could be used like the “MyType[]” expression in 
> C.  Frequently it can be used as a function parameter without having to 
> specialize for each possible array length.  In other words, for a given 
> static array type “MyType * […, N, …]”, it can be passed into a function 
> parameter that is declared as “MyType * […, any, …]”.  Could there be an 
> automatic way to pass in the value of “N”, or would we have to resort to 
> using another function parameter or some other out-of-band information and 
> trusting the user to synchronize correctly?
> 
> It should be possible to pass in different-shaped arrays to said function 
> parameters with a reshape call, as long as the total number of elements is a 
> multiple of the span across the “any”-ed extent.  Should such a function 
> parameter also take a "[MyInnerType]” dynamic array objects, where 
> “MyInnerType” is what you get after stripping the outermost, “any”-ed, extent?
> 
> A flexible-ending struct is one with a flexible-ending type as its last 
> stored property.  A flexible-ending enum is a enum with attributed cases and 
> at least one case ends its tuple with a flexible-ending type.  
> Flexible-ending types cannot appear anywhere else as a stored property in a 
> struct or enum.  Should we use “final” to mark a struct’s flexible ending 
> property?  Somehow adapt this for enums too?  (Right now, “final” is only 
> used for classes.)  Flexible-ending structs and enums can be used in function 
> parameters too, allowing different lengths for the same parameter.  Like 
> static-arrays, a struct or enum that matches a flexible function parameter 
> except that its would-be flexible part is fixed can be passed through said 
> parameter.  (It’s the same rule since all flexible struct and enums have to 
> have a nested flexible array at their end.)
> 
> Besides as function parameters, a flexible-ending object can be declared 
> inside a function/method or as a global.  I’m not sure how to do heap 
> versions yet.  If the object is immutable (i.e. “let”), the initialization 
> block has to cover all the elements without using $0/$etc or “default:” so 
> the size can be determined.  I’m not sure how mutable objects are supposed to 
> work here.  I’ll need your ideas the most here, assuming we keep this 
> feature.  It was inspired by seeing code in Ada (discriminated record) and C 
> (“MyType[1]” as last field in struct, then allocate with malloc) doing this.
> 
> Oh yeah, a flexible-ending static-array, including those that are parts of 
> flexible-ending structs and enums, must have a inflexible base type.  
> (Otherwise lies madness.)
> 
> (If we keep this feature, maybe it should be limited to one-dimensional 
> arrays.)
> 
> — 
> Daryle Walker
> Mac, Internet, and Video Game Junkie
> darylew AT mac DOT com 
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to