Which is already interesting because (at least according to the docs on developer.apple.com) InlineArray does not conform to ExpressibleByArrayLiteral and does not have an initializer that protocol requires, so I guess it’s already using compiler magic for that.
This is discussed explicitly in SE-0453.
It makes sense to use compiler magic for literals anyway. It would be rather facepalm-y to have to allocate on the heap to initialize a stack-allocated type with a literal, though it seems like even that could be avoided while still allowing the ExpressibleByArrayLiteral conformance. Unless I'm remembering wrong, variadics in a function declaration are actually treated as Tuples "under the hood" so I'd expect Array literals to be able to be handled without heap allocation by the compiler (or am I also misunderstanding how Tuples are allocated?).
Aren't variadics treated as Arrays under the hood?
If I was remembering it backwards, that would explain why they did it the way they did.
Count me in the "x was better" camp. I'm fairly neutral on "of" - I guess it seems weird to me to put an actual word into a type sugar. "x" just feels more appropriate, especially given its use in llvm.
I get that [5 x 5] looks similar to "five times five", but the pitch is for the type sugar, not the value sugar. There's no reason the value sugar needs to use the same syntax, especially if it will also be applicable for other types. (That said, I'm not really concerned about using "x" for both)
I do agree we need some kind of type sugar though, and if "of" has to be the compromise then so be it.
One thing that popped in my mind recently was how introducing a value literal syntax with of is one step towards introducing Python-like list comprehension. Now, that's quite a large leap and I'm in no way saying it's a slippery slope, but I can see proponents of comprehension pointing to the value literal syntax as a foundational justification for it.
It would be great to take into account the 'syntax friendliness' of new Swift features with respect to 'find-and-replace' operations and 'regular expressions'. Since regular expressions are commonly used not only in linters but also for 'find operations in IDEs', It would be nice that new language features remain easy to search and refactor. This consideration could be part of the evaluation criteria for future Swift language proposals.
Kind of, but this feature is an many ways the opposite of a python list comprehension in terms of use-cases and flexibility (let alone the fact that it’s defining a type here and not a value).
That is a good thing for InlineArray (its strict use cases are useful and legitimate, also to me directly, FWIW). But another potential downside to this sugar proposal.
Reordering the generic parameters is discussed in the InlineArray proposal's alternatives considered.
Late to this topic, so sorry if this was already discussed, but I didn't see this variation in the alternatives considered section of the proposal.
I agree with the sentiment that sugar would be nice for multi-dimensionality, but any sort of "a _ b" seems to invite confusion to me. Reading some of the user comments, it seems natural for people to express "x many things" using parenthesis. Obviously that's a bit overloaded with function calls and math operations. But since we're already used to array syntax using brackets [], why not just do a literal numeric prefix?
The examples then become:
// Nesting -
let fiveByFive: InlineArray<5, InlineArray<5, Int>> = .init(repeating: .init(repeating: 99))
let fiveByFive: 5[5[Int]] = .init(repeating: .init(repeating: 99))
// Inferring size from context
let fourBytes: _[Int8] = [1,2,3,4] // InlineArray<4, Int8>
// Inferring type from context
let fiveIntegers: 5[] = .init(repeating: 99) // InlineArray<5, Int>
let fiveDoubles = 5[](repeating: 1.23) // InlineArray<5, Double>
// Inferring size and type from context
let fourIntegers: _[] = [1,2,3,4] // InlineArray<4, Int>
Since the size is intended to be specified at compile-time, it must be an integer literal. And I don't think there's currently any legal way of using types inside of brackets [] other than for declaring an array type anyway, so doesn't seem like there should be any confusion to the compiler or the human.
Complex Types
Once you start getting into more verbose types, some people may desire parenthesizing the rhs of of to more explicitly call out the grouping... Imagine a fixed-size array of closures each returning a fixed-size array...
let fiveClosures: [5 of ((Int, String)->[2 of MyClass<String>])]
In this case, the brackets already give the separation, obviating that need:
let fiveClosures: 5[(Int, String)->2[MyClass<String>] ]
Mixing fixed and dynamic arrays
In the cases of mixing fixed size and dynamic arrays...
let fixedArrayOfDynamicArray: 5[[Int]]
let dynamicArrayOfFixedArray: [5[Int]]
versus
let fixedArrayOfDynamicArray: [5 of [Int]]
let dynamicArrayOfFixedArray: [[5 of Int]]
There's perhaps a danger of being too concise, but I feel like these are equally understandable (or not understandable, depending on your perspective
)...
Additional feature?
Size inferred from context
There's also perhaps a minor benefit in the case of inferred sizes...
The example above showed using an underscore, following the example given in SE-0483:
let fourBytes: _[Int8] = [1,2,3,4]
let fourIntegers: _[] = [1,2,3,4]
Using this notation, we could perhaps drop the underscore and default to InlineArray for let cases.
let fourIntegers: [] = [1,2,3,4] // equivalent to InlineArray<4, Int>
But I think this is only advantageous if the "upgrade" cost of switching from InlineArray to Array at point of need is negligible, but I'll defer to someone more knowledgable in that area:
var dynamicIntegers: [Int] = fourIntegers // Create Array<Int> and assign contents of InlineArray<4, Int>
Arguably this automatic behavior could still be done with the of syntax, but because there's a strong correlation between of and InlineArray, I feel like it would be a much bigger surprise.
Crazy idea?
By extension, even in var cases:, perhaps the compiler could detect based on usage whether any dynamic features were actually used by the array and automatically switch to there's some things that could be done to dynamically determine whether InlineArray or Array is desirable?
func assignmentStaysAsInlineArray() {
let fourIntegers: [] = [1,2,3,4] // equivalent to InlineArray<4, Int>
var anotherFourIntegers: [] = fourIntegers // equivalent to InlineArray<4, Int> because size was never mutated
anotherFourIntegers[2] = 12
return
}
func assignmentUpgradesToArray() {
let fourIntegers: [] = [1,2,3,4] // equivalent to InlineArray<4, Int>
var anotherFourIntegers: [] = fourIntegers // upgrades to Array<Int> with content assigned from InlineArray<4, Int> because size is mutated
anotherFourIntegers.append(12)
return
}
Sounds hard to do to me, and not sure if it's worth the effort. But food for thought...
While I realize this could be said of any type inference, this scenario seems much easier for the compiler to reason about than for the programmer. I feel like it might be past the line.
Thank you to everyone who participated in this review discussion! The proposal has been accepted:
Holly Borla
Review Manager