[Pitch] InlineArray type sugar

Like rauhul, I question the relevance of devoting so much energy to this topic of InlineArray syntax sugar at this time.

I would rather see this significant amount of energy being spent on addressing the real need for C interop support for InlineArray, which seems to have been relegated to the back burner.

2 Likes

I just had a fun thought this morning. Not sure if it is a serious one, but maybe.

Consider that [Int] is sugar for Array<Int>.
It seems reasonable, then, to wonder if the "stuff inside the angle brackets" could and should be the same "stuff inside the square brackets."
By that train of thought, the sugar for InlineArray<3, Int> could be [3, Int] (comma).
Of course, by itself, there is some ambiguity here if not used in type position.

But!—we have said that we care very much about communicating that this type stores its elements inline. Perhaps there is some way to depict something being "inline"?
Maybe, we literally put it inside the lines: |[3, Int]|—so, [...] is an array, and |[...]| is an inline array...

7 Likes

I think that would be source-breaking for the absolutely unhinged people who don't surround their arithmetic/bitwise operators with whitespace, because this (presumably meaning "set x to an empty inline array of 3 Ints") already has a different meaning today:

x=|[3, Int]|()
// parses as
x =| [3, Int] | ()
8 Likes

I'd also bristle at this because one of the few things more annoying than editing balanced syntax punctuation is editing multi-character balanced syntax punctuation. :sweat_smile:

5 Likes

How about (ab)using Verilog syntax? Maybe:

var a: [* 5, Int ]

This would also open another can of worms


Since riffing on your suggestion seems to be this morning's game, I'll just jump in too:

You could consider inverting from |[3, Int]| to [|3, Int|] and then to just [|3, Int], eliminating the nested delimiter complication.

A different approach would be to morph from InlineArray<3, Int> to [<3> Int]. That sort of preserves the 3's backstory.

1 Like

Well, it can be, but we are the language which (brilliantly, in my view) innovated

let x = ######"""
  Raw multiline string!
  """######

:slight_smile:

5 Likes

Speaking of “#” 
what about this?

var x: [3 # Int] = [1, 2, 3]

It even works with the count, element type, or both being inferred:

var x: [# Int] = [1, 2, 3]

var y: [3 #] = [1, 2, 3]

var z: [#] = [1, 2, 3]

The proposal mentions# as an option among the “arbitrary punctuation”, but
 it’s the number sign, so it’s not really arbitrary.

9 Likes

This is the first one I've liked, specifically because of this inference option that still looks good.

yeah, and lotta lines too - - / /

let matrix2: InlineArray = [
  [...] as InlineArray,
  [...],
]

I think even with the above two for type inference and not for static C or metal like declarations and using operations between literals and types is not aesthetically and cognitively good

A stated by Ellie

But Swift follows readability with syntactical Sugar
So as stated by tera

considering using _ for any dimension
like let _ = and _ =. decreases cognitive load

So I conclude by saying
Instead of various operations specified
what about considering

// Read as in math
let matrix: (6 3)[Int] = []
let features: (1024 10)[Float] = []
let elements: (_ _)[Int][String] = []

// readv as in physics stable for metal devs
// |...| probably mean vector's dimension
let viewProjectionMatrix: |_*_*_|[Int]= []

// or playfully as stylised math
// don't know wether its possible by compiler
let phylumSpices: {_ _}[String][String] 

The * and space operators are inter-changeable
if single [Type] is given it can be considered multipleTimes
And I believe it can't misbehave with Typecast Operator

I showed examples of Math, Chemistry, ML, Metal, and Biology
Please let me know if it can work
Bonus point it can convert to dictionary or nested dictionary if it can work

I wonder if overloading # in this way might cause ambiguities with expression macros.

You would know that better than I.

I’m kind of leaning toward “We don’t need to introduce sugar for InlineArray at this time” really.

Honestly, when I first saw this, I had to look up the date to check if it was written on the first of April.
It is actually the letter "x" isn't it?
Choosing this because "x" resembles a common operator symbol looks like character soup to me. That might be a cultural thing, and maybe this feels right to someone who got accustomed to perform multiplication that way in elementary school.
However, even in this case, I think I wouldn't want a future where types could be declared as [x x x x Int].

8 Likes

Thinking out loud here, but I wonder if different separators for the dimension vs the type (ie: [5 x 5 # Int], or a value version [5 x 5 # 0]) would allow for a syntax sugar that is less confusing when used in code that deals with matrices (for example, by avoiding [5 x [5 x 2]] to mean a 5x5 matrix of 2s instead of a 5x5x2 hypermatrix).

That would still allow using the x when it works best and even allow for a syntax for multi-dimensional arrays without introducing the "visual ambiguity" mentioned in the proposal.

For example, in some version of the N-body problem that uses N-dimensional InlineArrays instead of InlineArray+SIMD:

var mass:     [5 # Precision]
var position: [5 x 4 # Precision]
var velocity: [5 x 4 # Precision]
var force =   [10 x 4 # Precision.zero]

(Borrowing the # operator here because I liked it a lot, particularly due to how inferred element type / count looks).


On the topic of not introducing syntax sugar at all: IMO it would be really unfortunate that writing performant code that uses arrays of a known dimension at compile time requires the developer to be so much more verbose than the less performant Array version.

It could give the impression that InlineArray is some sort of niche and arcane optimization technique (like ContiguousArray). But there's code like the N-body problem above where it doesn't make sense (semantically, even) to be using a growable container like Array. It just isn't the right data structure.

Other languages like Rust and C have short and succinct ways of declaring variables of this type, I don't see why Swift shouldn't.

I know for many (most?) people, needing to reach for InlineArray would happen infrequently, so it almost makes sense not to introduce syntax sugar for it. The problem is, in some use cases (like numerical algorithms) developers will be using InlineArray all the time. So it's not like this type is going to be uniformly used sparingly across all kinds of developers.

Instead, there's going to be a lot of people that almost never use it, and a few people that use it all the time. IMO, the addition of the syntax sugar needs to cater to the second group, and at the same time avoid introducing any language-wide issues that impact the group of devs that never use InlineArray.

I wrote a lot of numerical (physics related) code in Swift while in college, so this topic hits home for me :grinning_face_with_smiling_eyes: A good, succinct syntax for this data structure can make-or-break whether the language feels good or not for this purpose.

1 Like

If there is a general agreement that a shorthand should be added, there is a spelling that I haven't seen yet:

5<Int> // equals InlineArray<5, Int>

Actually, my first thought was 5(Int), but parenthesis already have so many different meanings :joy:
As bonus, this spelling could also be compatible with tuples (and maybe even other things, like arguments):

2<String, Int> // (String, Int, String, Int)
let x: (String, Int, String, Int) = 2<"Text", 5>
print(3<"Hello">) // HelloHelloHello

It occurs to me that the likeness of x to a variable name could be alleviated to a certain extent by using a capital X instead:

let fiveIntegers: [5 X Int] = [5 X 99]
let xIntegers: [x X Int] = [x X 99]
let xxIntegers: [x * x X Int] = [x * x X 99]

Of course, keywords are usually lowercase, so it's still a bit strange.

I really, really hope we don't end up with x as pseudo-operator. Too much room for ambiguities, IMO. I'd prefer basically any other special character over it. Some possibilities I'd honestly find more acceptable: !,@#$%^&*|\/?;:~‹¥¹§¶

13 Likes

Let's not discount multi-character options too. Here's a multiply-arrow for instance:

let x: [5 *> Int] = [5 *> 99]

The more I think about it, the more I like of.

  • of doesn't need to interact with operator precedence
  • It has a natural shorthand for a repeated instance (var buffer = [1024 of 0])
  • Its meaning is quite obvious and clear
  • There are no issues with ambiguity or source breakage
  • It’s not x

I really don't like x. Not only is x a commonly used variable name, but using x instead of a proper multiplication sign is generally considered incorrect. And Swift already uses the asterisk, not x, as the idiomatic way to express multiplication.

10 Likes