Also agree this is a very nice addition, not much to add there (thanks! perhaps? ) - to add one more possibility to the bike shedding I'd suggest
StaticArray
(I am also in the camp that thinks Vector
is suboptimal).
Note: the pitched type is not static in the sense of StaticString
or StaticBigInt
.
Wanted to chime in as a person with a degree in mathematics that I personally prefer Vector
for the reasons described in the proposal
However, while I believe that the potential confusion as raised by the people above could be a valid reason to consider a different name, I nevertheless wonder how this would practically manifest itself: since Vector
's signature requires an explicit generic Int
parameter, I find it actually unlikely that people won't be able to figure out the difference â if one reads
struct Foo {
var items: Vector<16, Item>
}
I find it hard to believe that people would be expecting a dynamically-sized array here, the number makes it pretty obvious that there's some fixed size. Conversely, seeing Array<Int>
or [Int]
is generally already enough to imply that there's no fixed length.
This will fix a major pain point in C interop which will be most welcome. Also agree perhaps thereâs a better name than Vector.
Indeed, I think this is worth emphasizing. In Swift lingo, we've tended to use count to refer to the number of elements in a collection, whereas size tends to refer to the memory layout size.
What's being pitched here is an array-like type where its values have not only fixed size but also fixed count at instantiation.
There may also be a role for an array-like type with only fixed size but not count, but it is not what's been pitched here.
This is a long due addition to the language.
I like the typename Vector
, because it is short, and it means something that's familiar from linear algebra.
u: Vector <3, Int>
v: [3, Int]
w: [3 x Int]
u2: Vector <3, Vector <3, Q>>
v2: [3, [3, Q]]
w2: [3 x [3 x Q]]
struct Q {numerator: Int; denominator: Int}
I appreciate the effort and understand the need for a fixed-size collection type, but I have some reservations regarding the proposed approach.
The Motivation section begins by addressing the use of tuples, which is a valid and efficient solution available in Swift today. Tuples are particularly well-suited for this use case due to their static, inlined nature, resulting in a low memory footprint. However, the argument highlights the lack of collection-style APIs for tuples.
Itâs worth noting that there have been previous efforts, such as Slavaâs pitch on User-defined tuple conformances, aimed at addressing this limitation. Have you considered this as an alternative? While that proposal primarily covers Equatable and Hashable conformances, extending it to make tuples conform to ExpressibleByArrayLiteral, Collection, or MutableCollection could be equally effective in providing the desired functionality.
Itâs perfectly valid to prefer a nominal type over a structural tuple for this use case, but Iâd like to better understand the trade-offs involved, especially in comparison to a simpler alternative that avoids the complexity of introducing integer generics.
It would be difficult to come up with a definition of âmathematical valueâ that includes all the things mathematicians use vectors for while excluding those things you listed above. Remember, structs and enums are called algebraic data types for a reason ;-)
And in Common Lisp, vector is a subtype of array â arrays can be multi-dimensional in general, and a vector is just a one-dimensional array, which can itself be fixed size (they call that a âsimple vectorâ) or not.
âVectorâ doesnât really mean âgrowable arrayâ, itâs just something programmers made up. I suspect what happened is those languages that got fixed size arrays first called them âarrayâ, and when the fancy growable thing came along they just picked a random synonym without much thought (because programmers donât tend to think too much about these sorts of things).
The Motivation section begins by addressing the use of tuples, which is a valid and efficient solution available in Swift today.
I mostly need this for C interop, I need to work with things like uint8_t rom[209715200]
for emulators and VMs. Tuples just aren't ergonomic enough, for these sizes they aren't even supported! Even the larger supported sizes just bring the compiler to its knees.
Tuple conformances can only express the special case of a tuple that conforms to a protocol because all of its elements do. This works for Equatable and Hashable but doesnât make sense for, eg, Collection.
Both Stroustrupš and Stepanov² have written and talked about how this is exactly what happened in C++ (and, FWIW, both say that it was likely a mistake).
š "One could argue that valarray should have been called vector because it is a traditional mathematical vector and that vector should have been called array."
² "This was inconsistent with the much older meaning of the term in mathematics and violates Rule 3; this data structure [std::vector] should have been called array." See also https://www.youtube.com/watch?v=etZgaSjzqlU starting around 6:23
Just chiming in here with another large +1 for the feature and a huge -1 for the name. I much prefer FixedArray
.
I work a decent amount with geometry, and have come to be very familiar with points, rects, and vectors. The "vector" name proposed here is confusing terminology that will be unfamiliar to the vast majority of people who will ever use it.
Isnât Vector<3, Double>
a vector in the Euclidean geometry sense?
It certainly is if you endow it with a compatible addition and scalar multiplication.
Would it be appropriate for the Swift compiler to implicitly convert from Vector
to Unsafe{Mutable}Pointer<Element>
, but only when calling into C? I think the alternative â using existing APIs â is withUnsafe{Mutable}Bytes(of:_:)
and withMemoryRebound(to:_:)
for each vector argument.
Should vectors have explicit conversions to and from tuples? There might be users that need vectors and tuples, when migrating to the upcoming feature (without breaking ABI or source compatibility).
Surely, both swapAt
s needs to be a mutating method, not a borrowing one. I also agree that swapAt(_:with:)
really ought to be exchangeAt(_:with:)
.
+1 for the proposal as a whole, but I'm not 100% sold on the name. Not that it really matters since most of the time I'd be using the [T; N]
shorthand (or whichever other shorthand we pick if we decide to be objectively wrong :P)
I support adding this type to the standard library. It'll be useful for many performance-sensitive use-cases and I can't wait to use it .
I'm confused about how the consume
method is meant to work. The documentation says it "will call the closure Count
times", but only returns one Result
, which doesn't make any sense.
Naming thoughts
This to me is the crux of why I'm not super happy with Vector
as a name[1]. Coming from the perspective of graphics/3D rendering, I'd expect a Vector
type to have mathmatical operations defined on it and NOT be a collection (basically SIMD types but with generic size).
let a = Vector(1, 2, 3)
let b = Vector(4, 5, 6)
let result = a + b // should be Vector(5, 7, 9)
Additionally, I would love to see a type that is a fixed-count version of the proposed Span
type, and a name like RigidArray
would scale well to something like RigidSpan
.
P.S. I'm curious to know if something like this type would be useful for others. My particular use-case is in serialization, where certain chunks of a file have a size known at compile-time, (e.g. this header is always 24 bytes) and bounds-checking can be omitted at runtime.
I like
RigidArray
orFixedArray
âthey better communicate that this is just a special kind of array, and this naming scheme would work well with a potentialRigidSpan
,InlineArray
, orSmallArray
âŠď¸
Yeah, I prefer to explain this distinction in terms of the value being âstored inlineâ or not. âOn the stackâ vs âon the heapâ doesnât capture this properly, and also gets muddy when you have async functions and coroutines and so on, which technically might require heap allocation of stack frames.
Also in the ancient past, local variables of generic type were actually heap allocated, before we switched code generation to use dynamic alloca. While this was suboptimal, it was still only the âoutermostâ value being allocated out of line, so it was qualitatively different from a representation where all values are boxed.
It would be a different pitch for sure, but thereâs certainly a good case that Vector (or FixedArray or whatever) should actually conditionally conform to AdditiveArithmetic (and maybe other protocols) if its element type does, because there is only one possible implementation of this conformance that works.