I generally use a lot of
UnsafeBufferPointer<Element> for “performance” and really only return Swift native
Arrays for user-facing functions. However I’ve been thinking a lot about this given the recent horror stories going around and I’m wondering if
Arrays are actually friendlier to the Swift optimizer and I should prefer using them for reasons other than following Swift idioms. I can think of a couple reasons this might be the case:
Foundationis out of the picture,
Arrays have basically the same amount of indirection as
Buffers, with the slight difference that
Arraysstore their count and capacity inline in their backing storage, and so take up just one word on the stack. (While an equivalent vectorbuffer takes three.)
Arrays have value semantics and their contents obey
varmaking it easier for the optimizer to reason about them.
Arrays check the element indices and trap on out-of-bounds. I’ve written enough C and C++ to appreciate this feature and the penalty seems to be like less than 10% at worst. And it can always be circumvented using
Arrayslend themselves better to functional styles of programming and so are easier vectorize and parallelize.
Buffers need to be wrapped in
classtypes (because they need
deinit) when facing users, which effectively adds a layer of storage indirection. An
Arraycan be safely placed inside a
structtype when designing APIs. (a workaround: can use unmanaged buffer with header class type,, but at that point you’re basically rewriting
Arrays have reference counting overhead. I don’t know if the compiler knows to optimize this away if the
Arrayis local and never gets returned.
Swift doesn’t have a concept of a fixed-size array (not talking about stack-allocated arrays or contiguous tuples but certainly related). This means the count and capacity are redundant in these cases and I’m not sure the compiler can optimize based on knowledge the array never changes size the way a buffer pointer never changes size.
Arrays have value semantics and so you can’t opt-into shared, manually-managed storage the way you can with a
Buffer. This means
Arrays accumulate a lot of reference counting overhead if they move around enough, even if they never get mutated.
If you’re using
Foundation, then you have to remember to use
Array(ugh), and on top of that, weird things happen performance-wise when you use
ContiguousArray. Though this is only really relevant if you’re someone who uses a lot of
Can someone who knows more about the Swift optimizer comment on this?