Skip to content

Commit 748fee6

Browse files
committed
First draft of InlineArray sugar proposal
1 parent 8991630 commit 748fee6

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

proposals/NNNN-inline-array-sugar.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# `InlineArray` Literal Syntax
2+
3+
* Proposal: [SE-NNNN](0354-inline-array-sugar.md)
4+
* Authors: [Hamish Knight](https://github.com/hamishknight), [Ben Cohen](https://github.com/airspeedswift)
5+
* Review Manager: TBD
6+
* Status: **Awaiting Review**
7+
* Upcoming Feature Flag: `InlineArrayTypeSugar`
8+
9+
## Introduction
10+
11+
We propose the introduction of type sugar for the `InlineArray` type, providing more succinct syntax for declaring an inline array.
12+
13+
## Motivation
14+
15+
[SE-0453] introduced a new type, `InlineArray`, which includes a size parameter as part of its type:
16+
17+
```
18+
let fiveIntegers: InlineArray<5, Int> = .init(repeating: 99)
19+
```
20+
21+
Declaring this type is more cumbersome than its equivalent dyanmicaly-sized array, which has sugar for the type syntax:
22+
23+
```
24+
let fiveIntegers: [Int] = .init(repeating: 99, count: 5)
25+
```
26+
27+
This becomes more pronounced when dealing with multiple dimensions:
28+
29+
```
30+
let fiveByFive: InlineArray<5, InlineArray<5, Int>> = .init(repeating: .init(repeating: 99))
31+
```
32+
33+
## Proposed solution
34+
35+
A new sugared version of the `InlineArray` type is proposed:
36+
37+
```swift
38+
let fiveIntegers: [5 x Int] = .init(repeating: 99)
39+
```
40+
41+
## Detailed design
42+
43+
The new syntax consists of the value for the integer generic paramter and the type of the element generic paramter, separated by `x`.
44+
45+
This will be added to the grammar alongside the current type sugar:
46+
47+
> **Grammar of a type**
48+
> _type → sized-array-type_
49+
>
50+
> **Grammar of a sized array type**
51+
> _sized-array-type → [ expression `x` type ]_
52+
53+
Note that while the grammar allows for any expression, this is currently limited to only integer literals.
54+
55+
The new sugar is equivalent to declaring a type of `InlineArray`, so all rules that can be applied to the generic placeholders for the unsugared version also apply to the sugared version:
56+
57+
```
58+
// Nesting
59+
let fiveByFive: InlineArray<5, InlineArray<5, Int>> = .init(repeating: .init(repeating: 99))
60+
let fiveByFive: [5 x [5 x Int]] = .init(repeating: .init(repeating: 99))
61+
62+
// Inference from context:
63+
let fiveIntegers: [5 x _] = .init(repeating: 99)
64+
let fourBytes: [_ x Int8] = [1,2,3,4]
65+
let fourIntegers: [_ x _] = [1,2,3,4]
66+
67+
// use on rhs
68+
let fiveDoubles = [5 x _](repeating: 1.23)
69+
```
70+
71+
The sugar can also be used in place of the unsugared type wherever it might appear:
72+
73+
```
74+
[5 x Int](repeating: 99)
75+
MemoryLayout<[5 x Int]>.size
76+
unsafeBitCast((1,2,3), to: [3 x Int].self)
77+
```
78+
79+
There must be whitespace on either side of the separator i.e. you cannot write `[5x Int]`. There are no requirements to balance whitespace, `[5 x Int]` is permitted. A new line can appear after the `x` but not before it, as while this is not ambiguous, this aids with the parser recovery logic, leading to better syntax error diagnostics.
80+
81+
## Source Compatibility
82+
83+
Since it is not currently possible to write any form of the proposed syntax in Swift today, this proposal does not alter the meaning of any existing code.
84+
85+
## Impact on ABI
86+
87+
This is purely compile-time sugar for the existing type. It is resolved at compile time, and does not appear in the ABI nor rely on any version of the runtime.
88+
89+
## Future Directions
90+
91+
Analogous to arrays, there is an equivalent _value_ sugar for literals of a specific size:
92+
93+
```
94+
// type inferred to be [5 x Int]
95+
let fiveInts = [5 x 99]
96+
// type inferred to be [5 x [5 x Int]]
97+
let fiveByFive = [5 x [5 x 99]]
98+
```
99+
100+
Unlike the sugar for the type, this would also have applicability for existing types:
101+
102+
```
103+
// equivalent to .init(repeating: 99, count: 5)
104+
let dynamic: [Int] = [5 x 99]
105+
```
106+
107+
This is a much bigger design space, potentially requiring a new expressible-by-literal protocol and a way to map the literal to an initializer. As such, it is left for a future proposal.
108+
109+
## Alternatives Considered
110+
111+
The most obvious alternative here is the choice of separator. Other options include:
112+
113+
- `[5 * Int]`, using the standard ASCII symbol for multiplication.
114+
- `[5 ⨉ Int]`, the Unicode n-ary times operator. This looks nice but is impactical as not keyboard-accessible.
115+
- `[5; Int]` is what Rust uses, but appears to have little association with "times" or "many". Similarly other arbitrary punctuation e.g. `,` or `/` or `#`.
116+
- `:` is of course ruled out as it is used for dictionary literals.
117+
118+
Note that `*` is an existing operator, and may lead to ambiguity in fuure when expressions can be used to determine the size: `[5 * N * Int]`. `x` is clearer in this case: `[5 * N x Int]`. It also avoids parsing ambiguity, as the grammar does not allow two identifiers in succession. But it would be less clear if `x` also appeared as an identifier: `[5 * x x Int]` (which is not yet permitted but may be in future use cases).
119+
120+
Another thing to consider is how that separator looks in the fully inferred version, which tend to start to look a little like ascii diagrams:
121+
122+
```
123+
[_ x _]
124+
[_ * _]
125+
[_; _]
126+
```
127+
128+
Beyond varying the separator, there may be other dramatically different syntax that moves further from the "like Array sugar, but with a size argument".
129+
130+
For multi-dimensional arrays, `[5 x 5 x Int]` was considered but introduces visual ambiguity without being a radical improvement.
131+
132+
The order of size first, then type is determined by the ordering of the unsugared type, and deviating from this for the sugared version is not an option.
133+
134+
In theory, when using integer literals or `_` the whitespace could be omitted (`[5x_]` is unabiguously `[5 x _]`). However, special casing allowing whitespace omission is not desirable.

0 commit comments

Comments
 (0)