Now with the landing of fixed sized array being discussed we may have first class currency types for matrices and vectors (in standard library!), having "vector" name to denote two different things would be confusing. Note that you may want to use both kind of vectors in the same file, so avoiding import statement might not be an option.
I like FixedSizeArray
. WGSL, for example, distinguishes between fixed-size arrays (array<T,N>
) and runtime-sized arrays (array<T>
).
i donât think this is a particularly original insight, but iâll add it here for weighting purposes:
if the proposed type supports elementwise arithmetic and all the other operations one would âexpectâ a GLSL-style vector type to support, then i am +1 on naming it Vector
.
if it does not support those operations, then i am â1 on naming it Vector
. in that case, i think Block
is a perfectly suitable alternative and i think the likelihood of confusion with a âcode blockâ is minimal.
we should not use âyou can just define the arithmetic operations in an extensionâ as a justification to name it Vector
. although it is often unavoidable, i do not think it is a good idea to encourage people to get into the habit of defining a lot of public extensions to types they do not own.
Iâm not strongly against Vector
, but as long as we have Array
, I prefer ConstantSizeArray
. IMO it is not verbose. If spelling fatigue is a concern, syntax sugar (e.g., [2 * Int]
) should do.
What is your evaluation of the proposal?
+1. Vector
is both a great name and a much-needed type for performant and safe Swift code.
Is the problem being addressed significant enough to warrant a change to Swift?
Absolutely. The lack of ergonomic containers for fixed-size data has been a long-term problem in Swift and is particularly painful for embedded use cases.
Does this proposal fit well with the feel and direction of Swift?
Yes.
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
I have used Swift, Rust, and C++ in professional work. Compared to the constructs in the other two languages, Vector
has filled most of my needs. The primary missing piece I've encountered is an ergonomic way to get a &Span
and &mut Span
from Vector
.
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
I did an experimental adoption of Vector
from the PR toolchains into an existing shipping Embedded Swift codebase that previously used Array
.
Converting to Vector
was straightforward and allowed me to eliminate the need for a heap entirely and reduce the final application's code size.
On naming: The name Vector
felt completely natural, and I felt no need for sugar syntax. (I also personally don't want to think about supporting even more sugar syntaxes in my Swift macros.)
On API: I found that not having collection/sequence APIs didn't matter much to me. The two most interesting APIs I needed to add were:
extension Vector {
public func padded<let newCount: Int>(
with paddingElement: Element
) -> Vector<newCount, Element>
}
extension Vector where Element == UInt8 {
public init(utf8: StaticString)
}
This makes perfect sense to me. I was quite undecided (and frankly not really that engaged) with thinking about fitting name, but John's point makes me see this type in a very different light.
From that perspective StorageOf<N, T>
or similar makes a lot of sense: This won't be your new "fixed size array" currency type, it won't be passed around in APIs a ton, it just provides efficient storage for these things. And it potentially won't end up being the anchor point for any fancy math stuff or "collection 2.0" APIs.
Until this is figured out, wasting the name Vector
on it feels premature. A Vector
, whatever it's true meaning will end up being in the future, can easily be implemented using a StorageOf
as its guts, but provide a more specialized API surface.
As someone who writes a bit of graphics code on the side, the idea of the classic game engine type Vector3
being isomorphic to Vector<3, Double>
in Swift is very appealing to me. But as others upthread have mentioned, since this is more of a "guts" type your actual Vector3 implementation would wrap as an implementation detail, that makes me turn against the name Vector since I selfishly want that name available for the inevitable "clean" interface for graphics workflows (:<
I get the point, but it doesnât justify introducing an unthoughtful name. It will stick with us for the rest of our lives. I donât see how StorageOf
is less attractive than ConstantSizeArray
(or its variants). Take CollectionOfOne
as an example: it is what it says to Swifters, rather niche, and requires knowledge to use effectively. Very few would reach for it, but it aligns with Swiftâs vocabulary.
+1 proposal
Don't have strong feelings about the name.
I kinda do like the mention up thread of Vect because it just short circuits my brain from immediately assuming it's a Graphics type.
I don't mind SizedArray, ("Fixed" without "FixedSize" makes me think its actually Static) but then I'd pretty quickly start to assume that it will behave like Array in other ways. I'd be able to do lots of things with it based on Collections that it won't have right out of the box... including that I'd be able to determine it's size at runtime.
Selfishly I'd prefer not a super duper longer name though, because I'm actually going to use it a bunch, but I guess that's what type aliases are for.
I have a question about bound checking in Vector
. The proposal acknowledges the overlap with tuples for some scenarios and mentions how Vector
improves the ergonomics as it adds, among other things, dynamic indexing (yay!). However, I wonder how Vector
compares with tuples when indexing is not dynamic, but rather statically known.
For example, am I correct in thinking that updating an API such as this:
func kineticEnergy(speed: (Double, Double), mass: Double) -> Double {
return 0.5 * mass * pow(sqrt(pow(speed.0, 2) + pow(speed.1, 2)), 2)
}
To this:
func kineticEnergy(speed: Vector<2, Double>, mass: Double) -> Double {
return 0.5 * mass * pow(sqrt(pow(speed[0], 2) + pow(speed[1], 2)), 2)
}
Would mean that statically indexing speed
would no longer be guaranteed at compile-time to be within bounds?
If so, will it stay that way? Is there a chance to emit a compiler error when a Vector
is indexed with a integer literal out of bounds for the type?
And, from a performance point of view, is the compiler guaranteed to be stripping off any bound checks code from static indexing? (I imagine it is, but I figured I'd ask anyway).
And since the proposal is mentioning InlineArray
, my opinion is shifting even more toward XYZArray
.
âą ConstantSizeArray
for Vector
âą ConstantCapacityArray
for InlineArray
I donât mind "constant" vs. "fixed", but "constant" somehow feels more natural to me, especially with that let
in the generic parameter declaration.
The term "inline" is really descriptive of the special property of this type. I don't like that it's an adjective. But one could imagine the call site making sense: Inline<3, Int>
reads as "inline 3 ints". It's ... really accurate? But some form of a noun would be nice.
I'm thought one usually uses Float
instead of Double
for video game vectors. The only reason why Vector3
couldn't be a type alias for Vector<3, Float>
is because it should probably be aligned like SIMD4<Float>
(although, I don't think you can do that without wrapping it in a C struct anyway). All of the relevant Vector operations could easy be defined in extensions of Vector where Element: {Numeric/BinaryInteger/FloatingPoint/etc}
Actually, if Vector
supports lengths of 0
, then you could force the proper alignment by having a field of Vector<0, ThingYouWantTheAlignmentOf>
As currently implemented, Vector<0, T> is treated as an empty type so has no impact on the enclosing type's layout as with other empty types.
I didn't realize Swift and Rust diverged on whether empty type effected alignment. Probably because all of the empty types currently in Swift would have had an alignment of one in Rust anyway.
Another alternative name: The term "Buffer" is already used in the Swift Standard Library -- a "buffer pointer" is a pointer and size referring to a block of typed memory, so it would seem natural for such a block of typed memory to itself be called a "Buffer."
Another point I've not seen mentioned so far: This particular type requires that every element be initialized -- Vector<17,AnyObject>
must start life with 17 initialized object references. The design for a type that does not require every element be initialized is a lot less obvious (to me, at least), but I wonder if we want to reserve space in our naming discussions for future such types?
Just to be clear, and with my review manager hat on: the Language Steering Group does not generally find polls like this convincing (one way or another). To reiterate the guidance from the pitch thread:
I continue to strongly believe that Vector
is the obviously correct and best name for this type.
To reiterate some of my arguments from the original pitch:
"Vector" is an extremely well-established name for an ordered sequence of precisely n items, all of the same type. There is a particularly strong expectation that a type called "vector" would provide an array-like subscript operation. There is an equally remarkable lack of any expectations of resizability: when I see a type called "vector", I would not expect it to come with any insert
, append
or remove
operations. The name also rightly discourages operations like concatenation.
"Fixed-size array", "homogenous tuple" and similar descriptions are just that -- they are descriptions, not names. I feel particularly strongly that within Swift's world, the proposed Vector
type is neither an array nor a tuple, and so it must not be named either.
- In Swift, types called "arrays" come with resizing operations:
append
,remove
, range replacement, concatenation, etc. This does not feel negotiable to me: it is crucial feature of all array types (along with integer indices, a generic Element, and highly specific complexity expectations).Vector
cannot and will not provide such operations, and so it isn't an array type. - Swift uses name "tuple" to refer to the type product.
Vector
is a named type that is very much distinct from that.
Vector
is like a fixed-size array, and it is also like a homogeneous tuple; these phrases are useful when explaining the purpose of Vector
. But Vector
is distinct from Swift's arrays and tuple types. Vector
forms a separate category from arrays and tuples; I think its name must reflect this. Using either of these terms in the name of Vector
would cause continuing, unforced confusion. Names are important.
I remain entirely unconvinced (and really rather alarmed) by this line of argument. It seems clear to me that Vector
is going to be a highly prominent standard type. Even if it will not end up being used for data exchange across pure Swift code (which is an assertion that is not at all obvious to me), its natural role in C interoperability still makes it a core currency type, by definition.
But Vector
is not just for interop. In pure Swift code bases, Vector
will, at minimum, find a great deal of use as a building block, to serve as the type of stored properties. But unlike ManagedBuffer
, there is no obvious, inherent reason to avoid exposing Vector
-typed properties in public API surfaces, especially in @frozen
contexts -- so I expect it will get routinely exposed.
But that's just the narrowest possible use. I can also see Vector
getting used as the obvious currency type for any pure Swift function that needs to take or return a specific number of items of the same type. Defining a wrapper type (or taking separate parameters, or returning a labeled tuple) is often going to be a better overall option, but there are no absolutes in API design! Vector
will get used wherever we previously used to reach for C arrays or homogeneous tuples, typically providing a better replacement for both.
The Span
types (including consumable/appendable variants like OutputSpan
) are indeed going to be the universal currency types for passing data between generic data structures, replacing Unsafe[Mutable]BufferPointer
. Clearly Vector
isn't going to play much role there -- but types can and do productive work outside the container protocols! In particular, Vector
will certainly get added to the tool box as an alternative to homogeneous tuples.
What is the source of the confusion you are worried about here? (Does Swift have some other currency type called "vector"?)
This new type deserves to have a proper name that fits its role and nature; the proposed Vector
is precisely that.
I find the dismissal of the importance of this type and the provocative suggestion of using a "fifty-character" name to be quite outrageous. This is deeply troubling me; even if I accepted the (implausible) argument that Vector
is not going to see much use outside "niche" contexts, it remains a core primitive. There is no way it isn't worth giving it a good name.
In general I support the proposal in functionality and scope. My opinion on the type's name hinges on John's consideration:
If this is the caseâthat the proposed type isn't likely to be a currency type used directly in library APIs to the degree of other data structures like Array
or Set
âI'd advocate for avoiding the Vector
name (and its ties to mathematics and graphics libraries) in favor of one of the more generic structural names (Buffer
, Block
, and Inline
, all seem fine and learnable to me).
If this type is named Vector
, I suspect Swift packages will appear ("VectorKit" & company) which extend the Vector
type with a suite of mathematics APIs (var x, y, z
; func dot(_:)
; var magnitude
, etc. â you can imagine some of these may choose to declare retroactive conformances to protocols like AdditiveArithmetic
, too.)
If this type is not named Vector
, "VectorKit" will instead create its own struct Vector
which wraps an instance of this type and states its own (non-retroactive) conformances.
My concern is not that mathematical properties of vectors would be mistaken API additions for this type (the shape fits fine!): it's that the language should take a stance now, at the point of selecting the type name, on whether these APIs are conceptually appropriate to implement in the Standard Library (in a future proposal).
In short:
- If we believe the proposed type should itself house APIs appropriate for geometric use cases,
Vector
is a great name, and this proposal should stamp the Standard Library (or a blessed cousin) as the future destination for such APIs. - If we don't believe the proposed type should house geometry APIs, we should not name this type
Vector
, as doing so will result in the proliferation of public extensions to the same core type (probably with overlapping names but numerically disparate implementations) around the ecosystem of third-party libraries.
So you are possibly suggesting InitializedBuffer�