4 ms·
Rust doesn't just give you better guarantees. It gives you no runtime checking, and potentially even better performance than naive C, because it can automatical
by giornogiovanna 8y ago
Rust doesn't just give you better guarantees. It gives you no runtime checking, and potentially even better performance than naive C, because it can automatically tell LLVM when there is no memory aliasing going on.[0] Also, it gives you more confidence, because you can, for example, give out an array to someone and be sure that it won't be modified. And usually that kind of confidence is enough to write safe, race-free parallel code.
I don't think Swift's runtime exclusivity checks give you any of that.
[0]: https://github.com/rust-lang/rust/pull/50744 https://github.com/rust-lang/rust/pull/50744
- glhaynes 8y agoSwift arrays have pass-by-value semantics (under the cover, they use copy-on-write to keep performance good) and are thus safe to pass to functions without concern that they'll be modified. (Unless it's passed as an `inout` parameter, which requires a prepended "&" at the call site.)
- zozbot123 8y agoRust can use its own bovine superpowers here https://doc.rust-lang.org/std/borrow/enum.Cow.html https://doc.rust-lang.org/std/borrow/enum.Cow.html to enable developers to write code that's invariant over whether it's dealing with a fresh copy of something, or just a borrowed reference. So, it's not quite correct to say that Swift's use of copy-on-write gives it better performance. Rust can express the exact same pattern quite easily, and do it with far more generality.
- glhaynes 8y agoI don't mean to imply that Swift's array performance is better than anything other than what its own performance would be if it didn't implement COW. (My intention was to convey that the normal way of passing arrays comes with confidence that your copy won't be modified by the callee.) Rust sounds nice, I'll have to try it sometime.
- millstone 8y agoAre you sure that code expresses the same pattern? It looks like Rust's COW can only transition from Borrowed to Owned by making a copy. Swift's COW works by dynamically inspecting the reference count.
- giornogiovanna 8y agoRight, unless I'm mistaken, what you want is `Rc` with `Rc::make_mut`[0], not `Cow`. [0]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.make_mut https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#metho...
- millstone 8y agoSwift is designed to support dynamically linked code. If Rust had the same design goal, it would need a lot more dynamic checks too.
- dbaupp 8y agoDynamic linking isn't a problem. Rust's checking is local, and doesn't require checking things in other functions, just their signatures. Swift is the same. There are some cases were dynamic checks are required (e.g. with reference counting/shared ownership: class in Swift, Rc/Arc in Rust). Swift will automatically insert checks in these cases, whereas they have to be manually written into Rust code (via tools like RefCell). Swift and the APIs inherited from Obj-C use a lot more reference counting that Rust does by default, plus it's more difficult for the programmer to reason about the checks (e.g. to be able to write code that avoids them, to optimise) when they're implicit. In summary, Rust and Swift have essentially the same rules, but Rust requires manual code to break the default rules, whereas the Swift compiler will implicitly insert those necessary checks (in some cases).
- millstone 8y agoThat's the point: with dynamic linking the static signature encodes too much. In Rust sometimes you need to switch from FnOnce to Fn, or from Rc to Arc. These changes are binary incompatible. You have to recompile every client. Swift can't tolerate that restriction. UIKit doesn't want to have to pick from among Fn/FnOnce/etc for every function parameter, and commit to it forever. Swift types and functions need to evolve independently from their clients, so static checks are insufficient. That's why you see more dynamic checks. If Rust had the same dynamic linking aspirations it would insert more dynamic checks as well.
- giornogiovanna 8y agoThis doesn't sound like a very good example. Fn inherits FnMut inherits FnOnce, so a library should just ask for the freest one it can support. Usually that just falls out of the meaning of the function. For example, a callback should only be called once, so you ask for an FnOnce, or maybe some function will be called in parallel, so you ask for an Fn. And with Rc, RefCell, Arc, etc. a dynamic approach is also pretty well-supported.