And I was thinking why did they make Swift for low level usage if they were going to use Rust.
And I was thinking why did they make Swift for low level usage if they were going to use Rust.
Swift is great for application programming, but for low-level performance-critical systems programming it’s currently a huge pain in the rear. Swift’s philosophy is basically “give everything a Python-like level of dynamism, and then heavily inline/optimize out when statically possible.” For instance:
- Swift’s memory management is based on reference counting. It’s usually convenient and efficient (and lets you do cool things like copy-on-write), but when you know more about your object lifetimes than the compiler, the unnecessary retain/release traffic gets really annoying and is not easy to avoid.
- Swift’s generics are dynamic by default, which involves wrapping up every object into a possibly-heap-allocated container and using dynamic dispatch for everything. Usually the compiler will inline/specialize generics, but there’s no guarantee, especially when calling generics across module boundaries (due to ABI stability restrictions). Rust/C++ exclusively uses compile-time template instantiation, which is a little less flexible and doesn’t guarantee ABI stability but it always guarantees unimpaired performance. See [0] for a more detailed comparison.
- No stack-allocated arrays in Swift; all collections are reference-counted and stored on the heap.
- Still no async/await (or any real concurrency model at all) in Swift; it’s planned to be available in the next year or two. This could be a big deal for a networking team.
[0]: https://thume.ca/2019/07/14/a-tour-of-metaprogramming-models...
You're right about the dynamic dispatch, but both specialized and unspecialized generics use the same memory layout. While unspecialized generics have to compute the layout dynamically if needed, there's no boxing required. If this were not the case, specialized and unspecialized code would not be able to interoperate (and as you said, this is a requirement because of ABI boundaries).
> - No stack-allocated arrays in Swift; all collections are reference-counted and stored on the heap.
There's a compiler optimization pass which stack-allocates reference counted objects with a known lifetime (which includes the backing storage for arrays). However, just as with generic specialization, this is a best-effort optimization and is not guaranteed to actually take place.