(tldr: inline + repeat is viable and arguably preferable, and does not suffer from ambiguity of the count)
Let's be fair to the proposal for repeat. The phrase is "repeating {something} {some number of times}".
The current usage in Swift for initializers disambiguates the count explicitly: init(repeating: {something}, count: {total number})
The same is true for the proposal for repeat usage in InlineArray, where the requirement is to put the count type parameter first. (repeat is used here to distinguish the keyword form from the parameter name repeating.)
let ira: InlineArray<6, Int> = [6 repeat 7] // with count
let ira: InlineArray<6, Int> = [repeat 7] // count elided
So the problem is not the ambiguity of the count.
The problem is that repeat alone does not indicate that this is an inline array.
By default we should ask the literal to work on its own, both in meaning and in understanding:
let ira = [6 repeat 7] // what kind of array is this?
Here the sugar is not clear to the uninitiated (though it is probably clearer than x or or). Most uninitiated readers would read this as the stdlib Array.
That leads to the other problem with literal sugar: distinguishing members of a family of types with such repeating literals.
That led to being able say inline for the InlineArray literal sugar, notwithstanding the duplication, and use "repeat" only for the thing being repeated (not the count), in place of a series where the count is known. That also means "repeat" would work for repeating series of other series-consuming types.
So what are the rules for inline and repeat? This proposal is constrained to say the InlineArray count always precedes the type. It's fair to say that bidirectional type inference (B) should work for both count and element type
That gives us the following:
| Code |
Rule |
| IT |
inline is the distinguishing copula in the sugared type declaration |
| IL |
inline in the literal indicates this is an InlineArray type |
| BC |
count of the InlineArray can be inferred from the type declaration or the literal |
| BT |
The element type of the InlineArray can be inferred from the type declaration or the literal |
| SC |
the count of the InlineArray can be inferred from the count of a literal series |
| ST |
the type of the InlineArray can be inferred from the type of a literal series |
| RL |
repeat x in the literal indicates a series with a repeating literal where the count is otherwise given. |
| CP |
The count may be a type parameter from the scope |
| TP |
The type may be a type parameter from the scope |
The type declaration is:
| Type |
Rules |
| InlineArray<3, Int> |
|
| [3 inline Int] |
IT |
Here are the key combinations of type declaration and literal (imagine let ira {: type} = {literal}):
| Type |
Literal |
Rules |
| - |
[inline 0, 3, 5] |
IL, SC, ST |
| [inline] |
[0, 3, 5] |
IT, SC, ST |
| [inline] |
[3 repeat 7] |
IT, BC, RL, ST |
| [n inline] |
[repeat 7] |
IT, CP, RL, ST |
| - |
[inline 0, 3, 5] |
IL, SC, ST |
| - |
[n inline repeat 7] |
IL, RL, ST, CP |
If we also permit expressions in the repeat position where the index is available as a parameter:
| Code |
Rule |
| RE |
repeat e in the literal indicates a series with a repeating expression where the count is otherwise given. |
Then we also get repeat expressions:
| Type |
Literal |
Rules |
| - |
[n inline repeat { T($0) }] |
IL, RE, ST, TP, CP, BC |
| [n inline] |
[repeat { T($0) }] |
IT, RE, ST, TP, CP, BC |
Some might argue that repeat or inline could be implied in some of these cases, but I believe that forecloses other types, and that the original stdlib Array should be the default.
Alongside inline, imagine using the same keyword-type pattern for the following related types:
buffer: an inline array which can be resized within bounds on copy (where the count parameter is a Range<Int>)
slots: inline storage of different types with the same shape accessible via Int index (where the type parameter can be a constrained tuple or parameter pack?)
- and so on...
I believe this pattern would work for all such types.
I think both logic and discussion have shown "n x m" to be a defining example of ambiguity -- for the uninitiated. But x may indeed be preferable in a world where we can assume readers already understand the context and what x means. That could be fair: "Sugar" by definition is derivative, working as something easy to write for something otherwise hard to say. But the question is whether one must already know that association, and whether that particular brief expression scales across code.
Postfix '?', though considered sugar for Optional, is probably the conceptual form for readers, particularly given the corresponding infix ?? and postfix !. In that case, the sugar is primary or at least stands on its own. [ ] for Array is similar in this respect. Both are nicely orthogonal to the types they qualify and thus scale. But they might be rare if happy outliers.
I believe Swift should aspire to bidirectional inference between sugar and sugared, akin to what it does for types, and for the same reasons. Any proposal for a sugared form that does not clearly indicate the unsugared form (preferably without training) should have a higher bar for acceptance, minimally superiority in usage over alternatives. The loss of naive and local reasoning at scale is a burden.
I believe the combination of inline and repeat is an alternative, one not precluded by the question of count. The question (assuming it's still feasible) is whether its lack of brevity is made up for by the increase in clarity and teachability, the bi-directionality of understanding, and the ability to scale to related types.