[Second review] SE-0483: `InlineArray` Type Sugar

Hello, Swift community!

The second review of SE-0483: InlineArray Type Sugar begins now and runs through June 20, 2025.

After the first review generated a lot of constructive feedback from reviewers about proposed syntax and concerns that the "inline" nature of the storage -- the key factor in the naming decision for InlineArray -- is missing when using the type sugar. The proposal has been revised to include the following changes:

  • The separator changed from x to of.
  • The motivation section expanded to include a comparison of other languages that include type sugar for fixed-size arrays with inline storage.
  • The alternatives considered section now includes an extensive discussion of the suggestion to include explicit indication of the “inline” nature in the syntax.
Trying it out

If you'd like to try this proposal out, you can download a toolchain supporting it for Linux, Windows, or macOS using a recent main development snapshot from Swift.org - Download Swift and enabling the InlineArrayTypeSugar experimental feature.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  • What is your evaluation of the proposal?
  • Is the problem being addressed significant enough to warrant a change to Swift?
  • Does this proposal fit well with the feel and direction of Swift?
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at:

https://github.com/swiftlang/swift-evolution/blob/main/process.md

Thank you,

Holly Borla
Review Manager

35 Likes

-0.75. I like of better than x. I still don't love it, but I assume there are people much better at navigating that bikeshed than I am, so I'll defer to them ;)

I'm still not convinced that we want sugar for this. I actually really like having sugar for repeated values (in the future directions) and I think we should just implement that and then let type deduction do the rest for most cases. This has the benefit of also helping Array, which is a far more useful type. If we reimplement this proposal with just that I'd be +0.75, even with the choice of of.

4 Likes

A specific point that I’m just noticing:

A new line can appear after the of but not before it, as while this is not ambiguous, this aids with the parser recovery logic, leading to better syntax error diagnostics.

Looking back, this language was in the prior version as well, but I’d overlooked it. Is it still quite as relevant with of? I’m not aware of a precedent with other two-letter operators (as, etc.). Naively, it would seem that something that must always appear between brackets would be fairly straightforward to parse with good diagnostics.

5 Likes

The proposal says

[5; Int] is what Rust uses

This is incorrect — Rust uses [Int; 5] (which falls afoul of the generic argument ordering rule later in the document).

The proposal starts by saying people wanted inline to appear in the sugar, but then the alternatives omit the [5 inline Int] option that was discussed in the previous review.

I'm still -1 on this:

  • I don't think it's necessary. Even in embedded Swift I think sugar for Span and MutableSpan would be more commonly used than this. Certainly in Rust I use &[T] and &mut [T] far more than [T; N]. It's also unusual to write out nested types in full (the motivating example!), if you had to deal in such a type you'd probably create a typealias or a wrapper struct anyway.
  • I don't think it's extensible. There's clearly going to be more array-like types (eg. we already have ContiguousArray, and we'll likely soon want a variant that stores "at most N" elements inline, plus a count). I don't see how of helps us answer the question of a concise type and literal syntax for array-like types other than InlineArray; in fact, I think it makes it harder to answer those questions.

You might think "unnecessary" isn't a good reason to reject the proposal, but I think there's a cost to every such addition to Swift, particularly to the syntax (as opposed to, say, a module in the stdlib that isn't imported by default). If it's there, it'll be used; if it's used, people will come across it; if people come across it, they need to understand it. I think in that regard, InlineArray<5, Int> can probably be guessed at by most people who see it for the first time, where maybe [5 of Int] cannot.

16 Likes

On a similar note, I think it would be a good idea for whatever syntax is chosen here to be useful for other, non array fixed size types, and should fit the same pattern this syntax does for arrays. For instance, a fixed size dictionary of some kind. of is better than x for that, but I'm still not sure [5 of String: String] fully makes sense, though it's probably closure.

2 Likes

I for one am very happy with the change. And Inline array seems to me like a type I would use very often, so it's a welcome addition.

Just a side question. For this particular case:

let fourIntegers: [_ of _] = [1,2,3,4]

I presume that could also be written like this?

let fourIntegers: InlineArray = [1,2,3,4]
3 Likes

+1

A great addition to the language and the chosen syntax is clean and reads well. Not much longer than the Rust syntax, but something that more easily can be understood by someone coming across the construct in code for the first time.

2 Likes

I’m happy with the change from x to of. Perhaps mainly since of seems to be supported (or at least accepted) by far more people.

But I think it’s important to also proceed with the future sugar for a value literal. Hopefully this can be achieved with a new e.g. ExpressedWithInlineArrayLiteral protocol. And when used alone will be inferred to declare an InlineArray, but will also be possible to use for any other future fixed-capacity or fixed-size collection type. Just like a Set today can be initialized with an array literal.


var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]

Even more useful would be if the value literal could be extended to allow e.g. range operators and initializer expressions to specify the exact type stored:


let values: InlineArray = [200…250]

let digits = [10 of UInt8(48…)]

var buffer = [128 of UInt8(0)]

var row = [1024 of RGB(0, 0, 255)]

var sound = [512 of Double(0.0)]

This could then also be used with future types, like e.g. InlineFixedCapacityArray and a heap-allocated FixedCapacityArray, and even InlineFixedCapacitySet and FixedSizeDictionary etc.

2 Likes

+1 on this proposal, and I really like the arguments put forth by the authors.

This alternative is not omitted; it's addressed in the first section of the alternatives considered, titled Indication of the "inline" nature via the sugar.

Holly Borla
Review Manager

"The choice of of forms something close to a grammatical phrase ("an array of five ints")."

That's not how "of" works, though. It doesn't pluralize like "x" does.

"5x integer" means "5 integers".
"5 of integer" does not mean anything.*

The key here is that the x needs to be a suffix, and have whitespace after it.
"5 x integer" doesn't do the job.

This commonplace shorthand, [5x Int], has been brought up at least twice, but not addressed: SE-0483: `InlineArray` Literal Syntax - #383 by benrimmington

* [5 of Int] is learnable as broken English, however, and while it's worse than [5x Int], [5, Int], and [5-Int], it's better than [5 x Int], and I'd use it if [5x Int] doesn't work, like those other ones don't. I feel like it's better to recognize how weird of is, by spelling it like this, though: [5 o' Int].

I read it as an array containing “5 elements of type Int”

9 Likes

Something I think could really be helpful right now is given that we have gone through several discussions on if x or of or by or any other sugar keyword is best, that we focus our attention on making the case that an InlineArray deserves sugar.

I believe, that of could be considered settled. At least right now, for the purpose of making forward progress, could we consider it settled.

I am certain that there are areas in my code that would benefit from InlineArray, but from what I understand this is a very specific optimization that specific to domains where speed and efficiency are necessary. These are areas that I would love to learn more about and improve.

I do believe that speed and efficiency and lower level programming (such as embedded) are domains that Swift would like to occupy. Currently we will have two array types, Array (COW) and InlineArray (and I suppose kinda Set).

Given that the notation with x has prior art in LLVM

[5 x i32]

and ; in Rust

[i32; 5]

There seems to be precedence that such a notation AND the use-case are relevant. In the prior examples, this notation is used for what I believe are the InlineArray type.

Participants are concerned that there will be OTHER array types which may deserve the sugar more.

Additionally, some are concerned that there should be notation at all as InlineArray<5, Int> could be seen as sufficing.

So I have some questions:

  1. Does InlineArray<5, Int> suffice. Is there a reason to give this sugar.

  2. Should the notation [value of Type] be assigned to the InlineArray type or is there another type which deserves it? Is there a type similar to InlineArray which you are expecting to be implemented that would deserve this sugar more?

  3. What are areas in your code where InlineArray would be superior to any of the other array types?

  4. Expanding on (3.), where is InlineArray going to be most effectively used that other array types cannot occupy. Do you feel like compared to the other proposed types, InlineArray will be corner stone for efficient Array types and occupy an important domain (that you might not be involved in but rightfully can be seen as important)?

My current feeling is that the case has been made strong that InlineArray deserves its place and its sugar. Although I cannot come up with my own example of where I want to use it, because I do not require fast and efficient code yet, I do believe that it will be strongly needed.

I would love to hear from those who are more frequently designing fast and efficient code.

6 Likes

I'm very happy about replacing x with of, because the latter seems objectively clearer, more expressive and more reusable!

1 Like

I wouldn't say it doesn't mean anything, otherwise the saying "6 of one, half a dozen of the other" would obviously be incomprehensible :^)

+1 for either [5 x Int] or [5 of Int], or also (I'm not sure it's been suggested) [Int x 5] (and clearly "of" wouldn't work in this reversed case)

1 Like

I love this break down even if I disagree with the conclusion.

I feel like of is going to come into the language and people are going to feel like it is a generic multiplier like * in python.

python3
x = "hello"
print(x * 30)

people will try

let x = "hello"
print(30 of x) 

What would its behavior be?

And what object is 30 of x in that context if the langauge decides to allow it? Is it an InlineArray? and Array? Is it a Tuple? Some type that doesn't exist yet? That's an implementation detail so maybe the language designers reserve the right to do what they want in the moment.

I feel like people will expect both of the following to yield the same type of object because the later will feel like short hand for the former

let currentRepeatedArray = [1, 1, 1, 1, 1]
let quickerArray = [5 of 1]

My question is, what is that type now if this proposal goes through?

I would be interested in a pitch that brings of into the language as a short hand for a comma separated list of that item over and over.

I think working on a sugar for InlineArray AFTER that would lead the language to choices that are both more interesting and less confusing.

2 Likes

I want to point out that what you responded to was explicitly to gain answers to the following:

  1. Does InlineArray<5, Int> suffice. Is there a reason to give this sugar.
  2. Should the notation [value of Type] be assigned to the InlineArray type or is there another type which deserves it? Is there a type similar to InlineArray which you are expecting to be implemented that would deserve this sugar more?
  3. What are areas in your code where InlineArray would be superior to any of the other array types?
  4. Expanding on (3.), where is InlineArray going to be most effectively used that other array types cannot occupy. Do you feel like compared to the other proposed types, InlineArray will be corner stone for efficient Array types and occupy an important domain (that you might not be involved in but rightfully can be seen as important)?

However, to answer this

If one reads it as "30 instances of value x" it is clear that you would get precisely that. But you would need brackets

print([30 of x]) // ["Hello",  "Hello", "Hello", "Hello"…]

There has been discussion to allow Tuples (3 of Int) = (Int, Int, Int) and therefore (3 of 5) = (5, 5, 5)

But I don't think bare 3 of Int would have any meaning. The bracket describes the object type.

I am a proponent of allowing var a: [4 of Int] = [2 of 3, 1, 1] // [3, 3, 1, 1]

of was chosen specifically because of is less likely to suggest that the keyword is commutative unlike x, by, * et cetera.

They would be interpreted as

let currentRepeatedArray = [1, 1, 1, 1, 1] //Array<Int> = [1,1,1,1,1]
let quickerArray = [5 of 1] //InlineArray<5, Int> = .init(repeating: 1, count: 5) // [1,1,1,1,1]

I think that the following should be allowed.

var a: [Int] = [5 of 1] // Array with values [1,1,1,1,1]

In this case you just need to explicitly state the type because the default inference would be InlineArray otherwise.

4 Likes

Apologies for not answering your explicit questions. I side stepped them directly before because there is a fallacy in them that using InlineArray will consistently lead to faster more efficient code that I found a bit distracting, but that is not what I took as its heart. (Ben wrote some really good stuff about that in the last pitch (A, B).)

What I liked about it your post and what I think you've got right is that the question should now be about a potential sugar's ergonomics in code bases based on how the type will actually be used by people who will actually use it with of as the spelling. Some of that can't be done until its out there being used, in my opinion.

To pull out your answer to 3 as background information I use Swift in conjunction with C a lot. It is an absolute dream until one gets to C Arrays. I am very anxious for InlineArray to keep on keeping on so we can fix the TupleMuddle that the language has been in since the beginning. Although the current InlineArray doesn't get us quite all the way there, I have been watching it for a very long time with a lot of attention because it is a barrier between me and getting to use Swift for actual production code and also between me and feeling comfortable on trying to sell my embedded hardware / video pixel munching friends on Swift. The shady shady things I currently do with memcpy and assumptions about memory binding...

  1. InlineArray<5, Int> suffices just fine
  2. It should be consistent with the [1, ...., 1] syntax.
  3. See above.
  4. Also see above, although there are many other situations. Lots of good reading in the InlineArray pitch threads! Look for Vector, but I too would be interested in hearing people share again if they have the time.

Thanks for your all your answers to what I wrote. It is interesting to hear the perspective of someone who is less attached to the type. That's a useful perspective!

I don't think one should need the brackets in the print example. Variadics are a thing after all the below currently works.

let x = "hello"
print(x, x, x)

In the previous pitches lots of people mused about using of in different contexts.... I can go pull some of those out but maybe not this week! It's got a nice sentence like Swifty flow in some contexts. I missed of being less commutative, but I've missed things before. I'll go back and reread the pitch.

I think we disagree that it's okay for [1, 1, 1, 1, 1] and [5 of 1] to mean different things. which is a reasonable thing to disagree about.

I agree that var a: [Int] = [5 of 1] should be allowed ant that another thing mentioned above should also be allowed let fourIntegers: InlineArray = [1,2,3,4]

I would say the following would be what I'd like to be able to do / expect to have happen.

var currentRepeatedArray = [1, 1, 1, 1, 1] // Array
var quickerArray = [5 of 1] //Array
var repeatedInline: InlineArray = [1,1,1,1] //InlineArray
var quickerInline: InlineArray = [5 of 1] //InlineArray
var explicitQuickArray: [Int] = [5 of 1] //Array

I do not have a expectation or a burning desire for being able to use get any shorter InlineArray at this time. Type sugar doesn't get me much if it isn't the literal, and I think the literal this type sugar implies leads to confusions that could have significant negatives in performance because one of these type ISN'T always the best go to.

You don't seem to find that [1, 1, 1, 1, 1] != [5 of 1] as off putting as I do and that's good to know.

2 Likes

That doesn't represent the example, though.
"6 of one" is not synonymous with "6 ones".
"half a dozen of the other" is not synonymous with "half a dozen the others".

I haven't been able to come up with a example myself, of why "5 of Int" would translate to "5 ints", but I can get kinda close, so I bet someone who believed in the proposal could do better. The proposal isn't convincing without such an example.

It’s just shorthand for 6 instances of type Int or 6 instances of value 1

Swift isn’t English it is just inspired by English. The English meaning just gives you hints.

guard gives you a hint of what is happening in the code but it doesn’t read as English.

5 Likes