<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">[I’ve seen the WWDC 2016 Keynote and State of the Platforms videos. &nbsp;I haven’t seen any others so I don’t spoil myself before typing my ideas down. &nbsp;Apologies if this has already been covered.]</div><div class=""><br class=""></div><div class="">Is there any problem to adding fixed-sized arrays? &nbsp;From what I glanced here, it’s more like no one has gotten around to it and less like the very idea is hated.</div><div class=""><br class=""></div><div class="">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. &nbsp;This type of, well, type can be used when the baggage of length changing isn’t needed &nbsp;Such arrays are also a classic type since we started system-programming languages. &nbsp;(I was surprised by their absence in Swift when I first read the books.) &nbsp;They can be mapped to a vector processing unit’s built-ins.</div><div class=""><br class=""></div><div class="">This:</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class="">struct&nbsp;ArrayOf5&lt;T&gt; {<br class=""><br class="">&nbsp; &nbsp;&nbsp;let&nbsp;count =&nbsp;5<br class=""><br class="">&nbsp; &nbsp;&nbsp;var&nbsp;first:&nbsp;T<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;second:&nbsp;T<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;third:&nbsp;T<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;fourth:&nbsp;T<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;fifth:&nbsp;T<br class=""><br class="">&nbsp; &nbsp;&nbsp;init(array: [T]) {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;first&nbsp;= array[0]<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;second&nbsp;= array[1]<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;third&nbsp;= array[2]<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fourth&nbsp;= array[3]<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fifth&nbsp;= array[4]<br class="">&nbsp; &nbsp;&nbsp;}<br class=""><br class="">&nbsp; &nbsp;&nbsp;subscript(index:&nbsp;Int) -&gt;&nbsp;T&nbsp;{<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;get&nbsp;{<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;var&nbsp;preResult:&nbsp;T?<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;switch&nbsp;index {<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;0:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;preResult =&nbsp;first<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;1:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;preResult =&nbsp;second<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;2:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;preResult =&nbsp;third<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;3:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;preResult =&nbsp;fourth<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;4:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;preResult =&nbsp;fifth<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;default:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;preResult =&nbsp;nil<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;preResult!<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}<br class=""><br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;set&nbsp;{<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;func&nbsp;doAssign(destination:&nbsp;UnsafeMutablePointer&lt;T&gt;) {<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;destination.memory&nbsp;= newValue<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}<br class=""><br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;switch&nbsp;index {<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;0:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;doAssign(&amp;first)<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;1:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;doAssign(&amp;second)<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;2:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;doAssign(&amp;third)<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;3:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;doAssign(&amp;fourth)<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;4:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;doAssign(&amp;fifth)<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;default:<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;doAssign(nil)<br class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}<br class="">&nbsp; &nbsp;&nbsp;}<br class=""><br class="">}<br class=""></blockquote></div><div class=""><br class=""></div><div class="">shouldn’t be better supported than directly having built-in fixed-sized arrays. &nbsp;(I’ve wondered if we should have a library or built-in arrays. &nbsp;I’ve decided that even if we add a library, we still need the built-in.) &nbsp;Although I parametrized the type, altering the shape (right now 1 dimension of 5 elements) doesn’t scale since it requires lexical change. &nbsp;Internally, a built-in array type would be something like this, modulo optimizations and not having to come up with names for each element.</div><div class=""><br class=""></div><div class="">—————</div><div class=""><br class=""></div><div class="">[The following sections are my ideas about implementation; we don’t have to use them.]</div><div class=""><br class=""></div><div class="">What should array type expressions look like in code?</div><div class=""><br class=""></div><div class="">Since generics (currently) only use type-based parameters, we can’t do something C++-ish like “array&lt;T, 1, 4, 3&gt;”. &nbsp;I did have a thought of “[MyType; 5]”, but that seemed too close to current arrays. &nbsp;I was shocked to discover that Rust uses that syntax. &nbsp;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).</div><div class=""><br class=""></div><div class="">Since arrays are product types (I think), let’s use multiplication syntax:</div><div class=""><br class=""></div><div class=""></div><blockquote type="cite" class=""><div class="">var myArray: MyType * [6] &nbsp;// This is an array of six elements, each of `MyType`</div><div class="">var myArray2: MyType * [6] * [5] &nbsp;// This is an array of five elements, each a six-element array of `MyType`</div><div class="">var myArray3: MyType * [3, 4] &nbsp;// This is an array of three-by-four, each element of `MyType`</div></blockquote><div class=""><br class=""></div><div class="">The “[ SHAPE ]” syntax affects the type expression to its left. &nbsp;An empty list is not allowed since, although array-literal syntax allows empty lists, the subscript operation does not. &nbsp;Note, to keep the syntax regular, the first subscript when using “myArray2” is for five elements, i.e. “0..&lt;5”, and the second (if any) is for six, the reverse lexical order of declaration. &nbsp;This is because we don’t have C’s cute “declaration equals usage” type syntax. &nbsp;Also note that “myArray3” requires a single subscript call with two coordinates in it to dereference. &nbsp;Supplying only one coordinate is nonsensical. &nbsp;(“myArray2” is the other way when you want to dereference a “MyType” value.)</div><div class=""><br class=""></div><div class="">Of course, not using a shape expression gives you a zero-dimensional array (i.e. a regular variable) of your base type by default. &nbsp;(So, it would actually be "0 + extents(MyType.self)" dimensions.)</div><div class=""><br class=""></div><div class="">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. &nbsp;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.</div><div class=""><br class=""></div><div class="">——</div><div class=""><br class=""></div><div class="">What about row vs. column order?</div><div class=""><br class=""></div><div class="">If you stick with chaining one-dimensional arrays, you get only row-order, just like C (which can only do nested one-dimensional arrays). &nbsp;If you use a multi-extent shape expression, you can override the order:</div><div class=""><br class=""></div><div class=""></div><blockquote type="cite" class=""><div class="">var myArray1: MyType * [3, 4] * #rank[0, 1] &nbsp;// Default; row-order</div><div class="">var myArray2: MyType * [3, 4] * #rank[1, 0] &nbsp;// Reversed; column-order</div><div class="">var myArray3: MyType * [3, 4, 5] * #rank[0, 2, 1] &nbsp;// Scrambled</div></blockquote><div class=""><br class=""></div><div class="">The array literal attached to the rank command has to contain every value in 0..&lt;count exactly once. &nbsp;The position of the “0” value is the spacing with the longest span, “count - 1” is the adjacent elements level.</div><div class=""><br class=""></div><div class="">A rank command can only appear directly after a shape expression or an element type expression, and not after another rank command. &nbsp;The command’s literal must have the same length as the number of extents of the corresponding shape expression. &nbsp;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.</div><div class=""><br class=""></div><div class="">The rank command does not pierce type aliases; “#rank[]” is the only valid command for them. &nbsp;The alias itself can have a rank command, which affects all objects declared with that alias, and cannot be overridden. &nbsp;(If the alias doesn’t have a rank command, the index storage priority is fixed to the default.) &nbsp;Should a rank-stripping command be added? &nbsp;Should an rank command that pierces aliases and/or overrides previous ranks be added?</div><div class=""><br class=""></div><div class="">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. &nbsp;We should have a function that can reshape an array if the total number of the outermost non-static-array objects are the same. &nbsp;(The function could reshape a non-static-array type to a static array of one element with any nesting.)</div><div class=""><br class=""></div><div class="">(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.)</div><div class=""><br class=""></div><div class="">——</div><div class=""><br class=""></div><div class="">What about initialization?</div><div class=""><br class=""></div><div class="">I didn’t use initialization expressions before because it’s hard. &nbsp;We’ll have to work on this.</div><div class=""><br class=""></div><div class="">Zero-dimensional arrays (i.e. a regular non-static-array type) are iniitalized as usual.</div><div class=""><br class=""></div><div class="">A one-dimensional static-array gets initialized like a current dynamic array. &nbsp;But the syntax given below will also be accepted (with just one coordinate, of course).</div><div class=""><br class=""></div><div class="">For higher-dimensional arrays, we need something like:</div><div class=""><br class=""></div><div class=""></div><blockquote type="cite" class=""><div class="">[(0, 0, 0): myFirstValue, (2, 4, 1): mySecondValue, …]</div><div class="">[(0, 0): myFirstValue, (0, 1): mySecondValue, default: myDefaultValue]</div></blockquote><div class=""><br class=""></div><div class="">and/or:</div><div class=""><br class=""></div><div class=""></div><blockquote type="cite" class=""><div class="">var myArray: MyType * [3, 4] = { return 2 * $0 + 7 * $1 }</div></blockquote><div class=""><br class=""></div><div class="">(We can use “myParam1, myParam2 in” syntax for that last one too.) &nbsp;Can/could we have an array expression that is part (XX, YY) and part $0/$etc formula? &nbsp;Maybe with “_” and/or “case” and/or “where” to differentiate which elements get the $0/$etc and which ones get a “default:” phrase? &nbsp;Maybe the _/case/where could be used within incomplete (XX, YY)-style indexing?</div><div class=""><br class=""></div><div class="">——</div><div class=""><br class=""></div><div class="">Should there be flexible-ending arrays? &nbsp;Other value types?</div><div class=""><br class=""></div><div class="">Let’s say that at most one extent in a shape expression can be “any” instead of a compile-time integer expression. &nbsp;Let’s restrict the “any” dimension to be the rank-0 one, using “#rank” to override if you didn’t put the “any” first. &nbsp;Let’s call these flexible-ending static-arrays.</div><div class=""><br class=""></div><div class="">Flexible-ending static-arrays could be used like the “MyType[]” expression in C. &nbsp;Frequently it can be used as a function parameter without having to specialize for each possible array length. &nbsp;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, …]”. &nbsp;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?</div><div class=""><br class=""></div><div class="">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. &nbsp;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?</div><div class=""><br class=""></div><div class="">A flexible-ending struct is one with a flexible-ending type as its last stored property. &nbsp;A flexible-ending enum is a enum with attributed cases and at least one case ends its tuple with a flexible-ending type. &nbsp;Flexible-ending types cannot appear anywhere else as a stored property in a struct or enum. &nbsp;Should we use “final” to mark a struct’s flexible ending property? &nbsp;Somehow adapt this for enums too? &nbsp;(Right now, “final” is only used for classes.) &nbsp;Flexible-ending structs and enums can be used in function parameters too, allowing different lengths for the same parameter. &nbsp;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. &nbsp;(It’s the same rule since all flexible struct and enums have to have a nested flexible array at their end.)</div><div class=""><br class=""></div><div class="">Besides as function parameters, a flexible-ending object can be declared inside a function/method or as a global. &nbsp;I’m not sure how to do heap versions yet. &nbsp;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. &nbsp;I’m not sure how mutable objects are supposed to work here. &nbsp;I’ll need your ideas the most here, assuming we keep this feature. &nbsp;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.</div><div class=""><br class=""></div><div class="">Oh yeah, a flexible-ending static-array, including those that are parts of flexible-ending structs and enums, must have a inflexible base type. &nbsp;(Otherwise lies madness.)</div><div class=""><br class=""></div><div class="">(If we keep this feature, maybe it should be limited to one-dimensional arrays.)</div><div class=""><br class=""></div><div class="">
<div style="color: rgb(0, 0, 0); letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">—&nbsp;</div><div class="">Daryle Walker<br class="">Mac, Internet, and Video Game Junkie<br class="">darylew AT mac DOT com&nbsp;</div></div>
</div>
<br class=""></body></html>