15 ms·
How Swift Achieved Dynamic Linking Where Rust Couldn't
- deleted 7y ago[deleted]
- garmaine 7y agoWhy the swipe at Rust?
- chenglou 7y ago> Also for context on why I'm writing this, I'm just naturally inclined to compare the design of Swift to Rust, because those are the two languages I have helped develop. Also some folks like to complain that Rust doesn't bother with ABI stability, and I think looking at how Swift does helps elucidate why that is.
- gpm 7y agoI haven't read the article yet, but important context to this is probably that Gankra has a lot of experience with Rust. They literally wrote a lot of the book on unsafe rust... See their list of publications for some examples: https://gankra.github.io/blah/ https://gankra.github.io/blah/ (I found this while trying to determine if Gankra = Gankro, it turns out it does). Edit: Now that I've read it I can say I though they were pretty fair to both languages. This certainly isn't a comparison between them, but they made some legitimate criticisms of both when that criticism happened to be an interesting point of comparison. Really good article, I highly recommend reading it if you like low level compiler stuff.
- tedunangst 7y agoAdding back the word How softens the blow.
- spockz 7y agoThere is no swipe. It seems like a totally objective statement. There is no inherent (value) judgment here. The article is really well written and easy to digest. Especially if one has a bit of compiler background.
- masklinn 7y agoThere is a swipe though. The title can easily be interpreted as Rust having attempted and failed to implement dynamic linking, which I don't believe is true. Replacing "couldn't" by "didn't" would be much more objective and would not be interpretable as a value judgement.
- Gankro 7y agoIt's literally true that Rust tried and failed in the sense that Rust's early design was extremely similar to Swift's, polymorphic compilation and all, and it was thrown out when it didn't seem to work. Swift pushed on it harder, and got it to work. But it's less so true in the sense that the two teams had different use cases, and simply took divergent paths. Rust took the "easier"* path that limited expressivity in favour of a simple execution model that requires a minimal runtime, which in turn enabled them to focus on more interesting static analyses. Swift took the other path. * This may sound like a slight against Rust, but both the Swift and Rust folks who worked on this stuff agree that what Swift did is a comically huge amount of work in pursuit of a relatively niche use case (idiomatic-feeling system apis). There's only so much time in the world, and Rust spent its time on other problems.
- masklinn 7y ago> But it's less so true in the sense that the two teams had different use cases, and simply took divergent paths. Rust took the "easier"* path that limited expressivity in favour of a simple execution model that requires a minimal runtime, which in turn enabled them to focus on more interesting static analyses. Swift took the other path. > * This may sound like a slight against Rust, but both the Swift and Rust folks who worked on this stuff agree that what Swift did is a comically huge amount of work in pursuit of a relatively niche use case (idiomatic-feeling system apis). There's only so much time in the world, and Rust spent its time on other problems. That I completely agree with and don't think is a slight at all: the work you outlined for Swift to have a stable ABI was a humongous (and truly novel and original) undertaking, but because it's so large it needs a real motivation and an expectation of ROI, and I don't think that ROI was / would have been there for Rust: there is little chance that a system would be shipped with Rust as the system and application libraries baseline (in the sense of libraries which are expected to be consumed essentially only by rust, which is what a rust ABI would imply), so while there are use cases for a Rust ABI they're limited (safer plugins and the like, maybe a system-provided dynamically linked stdlib). On the other hand Swift is intended as the baseline applications language on all Apple platforms, meaning Apple has a large incentive to be able to ship and update swift-level libraries as part of their OS and other packages, in order both to reduce application bundle sizes and be able to update libraries as they go (without those libraries being limited to fairly shallow shims over C-level libraries where the actual meat would be).
- _bxg1 7y agoAdvantages and disadvantages were mentioned for both languages; for example Swift's "surprising performance cliffs"
- littlestymaar 7y agoThe author worked on both compiler (first Rust as a summer intern at Mozilla, then Swift at Apple and now back again on Rust at Mozilla). They're one of the best placed people to talk about the differences between these two language.
- Gankro 7y agoMore accurately I worked on stdlib stuff for both, with a focus on collections. It's just that this naturally pushes you into minoring in language design and majoring in the low-level details of the language. Plus it's hard to not pick this stuff up if you have to hang out with compiler people all day.
- littlestymaar 7y agoThanks for the clarification!
- an_d_rew 7y agoWhat a well written article! Thanks for taking the time to post it!
- saagarjha 7y ago> In the extreme case, we could make a system where everything is an opaque pointer and there's only one function that just sends things strings containing commands. Interestingly, Objective-C has other ABI issues…
- sandGorgon 7y agoSupporting both polymorphic and monomorphic compilation helped Swift a lot, but I think the key difference was ultimately just that Apple had a more significant motivation than Mozilla to pursue dynamic linking and way more resources to throw at this very hard problem. Interesting stand.
- saagarjha 7y agoAll of macOS's system libraries are dynamically linked, so there's just no way Swift could be used in the OS if it didn't do this right.
- sandGorgon 7y agoThe last part of the line reads (rather politically incorrectly) that Apple has more talent available to solve this problem.
- tinco 7y agoHow would it not?
- saagarjha 7y agoI have no idea of the amount of resources spent, so I'm not sure I can comment on that.
- zozbot234 7y agoOr they were just willing to accept a significant increase in language complexity, to deal with things that Rust just punts on by basically expecting you to stick to #[repr(C)] at your preferred dylib boundary. (Though, potentially, that #[repr(C)] could become e.g. #[repr(SomeArbitraryStableABI)], and there have been proposals to this effect.) And they did this precisely because of that perception that Swift "wouldn't be usable" otherwise.
- littlestymaar 7y agoGiven that the author is a Mozilla employee (working on Rust) and former Apple one (on Swift), I'd be surprised if your interpretation was correct.
- gdxhyrd 7y agoThe technicalities behind Swift's work on ABI stability are very interesting but I remain unconvinced developers care about ABI stability nowadays; outside security updates and the very basic layers (syscalls, WinAPI...). In the past, ABI stability was way more important for many companies because there were many more closed source dependencies, way less access to online updates, way less emphasis on CI/CD, etc. The argument for size by avoiding several std runtimes is strange in 2019, specially considering Apple's policy of deprecating things and forcing devs to update apps constantly.
- saagarjha 7y agoABI (and module) stability is a big thing for people shipping iOS frameworks.
- sedatk 7y agoABI stability benefits users too. It reduces payload sizes because runtime can reside in the OS as a shared library.
- gdxhyrd 7y agoI answered to that in the last paragraph. I don't see the appeal in 2019, in particular in the Apple ecosystem where backwards compatibility is not respected that much.
- 7y ago
- _bxg1 7y agoI really enjoy Swift's philosophy of setting up higher-level abstractions, and then pirouetting under the hood to get performance near the ballpark of C++ and family. I'm a big believer in "Just Works pretty-fast by default, optimal by deep-dive". Too bad Apple hasn't shown much interest in supporting Swift on other platforms; I know efforts exist but they all seem like second-class citizens. I don't really want to invest the time learning a new language that's locked to a single ecosystem.
- melling 7y agoSwift has been made available for Linux for the past four years: https://swift.org/download/#releases https://swift.org/download/#releases https://www.digitalocean.com/community/tutorials/how-to-install-swift-and-vapor-on-ubuntu-16-04 https://www.digitalocean.com/community/tutorials/how-to-inst... I’m not sure what’s missing as far as libraries, other than UIKit.
- _bxg1 7y agoDidn't realize the Linux version was offered through the official channels. That's something. Still, to truly compete it would need to have Windows support too. And ideally real buy-in from at least one other major tech company.
- shanev 7y agoIBM uses Swift for mobile apps https://developer.ibm.com/swift/2015/12/03/introducing-the-ibm-swift-sandbox/ https://developer.ibm.com/swift/2015/12/03/introducing-the-i... and develops Kitura (https://www.ibm.com/cloud/swift https://www.ibm.com/cloud/swift), a Swift web framework.
- nl 7y agoIBM is no longer offering that Swift mobile dev kit. The IBM Swift Sandbox is no longer available as of January 2018.
- nitwit005 7y agoI definitely see the desire to replace Objective-C, but the downside of ABI stability seems to be that it prompts a lot of worries about new features or optimizations affecting it. I hope this won't add too much sand in the gears.
- The_rationalist 7y agoDoes anyone know a good technical comparison of swift vs Kotlin (and eventually vs rust and typescript). I would like to see their singular features and their misfeatures.
- hellofunk 7y agoI think most notably is the different paradigms towards memory management. The syntax is very similar between the two languages, something like 80% identical, but that's trivial.
- skohan 7y agoHow do Kotlin's interfaces compare to Swift protocols? Being able to do things like provide default implementations in a protocol are some of the biggest Swift features for me.
- andrekandre 7y agoit’s not exactly the same thing, but you can kind of accomplish something similar to “swift protocols with default implementations” with abstract classes https://www.programiz.com/kotlin-programming/abstract-class https://www.programiz.com/kotlin-programming/abstract-class
- mojuba 7y agoI love Swift very much but every time I look at the disassembly view in Xcode while debugging, I lose faith in it bit by bit. With my (rather limited) knowledge of what a C or C++ program would compile into I have some expectations of what I'll see in Swift's case but the reality ends up being orders of magnitude more complex. Orders of magnitude is no exaggeration. For example this: (myObject as! SomeProtocol).someMethod() translates into hundreds of executed instructions, a bunch of nested calls that somehow end up in objc_msgSend (!) even though none of the objects on that line have anything to do with NSObject. Let alone ARC atomic acquisitions, etc. For one thing, Swift is hardly ready for application domains like audio, video or games. No doubt it can make the development process so much faster and safer, but also less performant by exactly that amount. Swift is beautiful, surprisingly powerful and non-trivial (something you typically don't expect from a corporate language, having examples of Java and C#), but the run-time costs of its power and beauty are a bit too high to my taste. A bit disappointing to be honest.
- zozbot234 7y ago> translates into hundreds of executed instructions My guess is that this would also be true under Rust, as soon as you start using some pretty common facilities such as Rc and RefCell. (Swift does essentially the same things under the hood.) That said, "hundreds of executed instructions" are literally not a concern with present-day hardware; the bottleneck is elsewhere, especially wrt. limited memory bandwidth (as we push frequencies and core counts higher, even on "low-range" hardware), so it's far more important to just use memory-efficient data representations, and avoid things like obligate GC whenever possible - and Rust is especially good at this.
- mojuba 7y ago> "hundreds of executed instructions" are literally not a concern with present-day hardware Depends on the context. I have that line in a very tight loop in a CoreAudio callback that's executed in a high-priority thread. It should produce audio uninterrupted, as fast as possible because the app also has a UI that should be kept responsive. Least of all I want to see objc_msgSend() in that loop. Of course I know I will remove all protocols from that part of the app and lose some of the "beauty" but then what's the point of even writing this in Swift? For most applications Swift is good enough most of the time. No, it's excellent. I absolutely love how tidy and clever your Swift code can be. Maybe a few things you wish were improved, but every language update brings some nice improvements as if someone is reading your mind. The language is evolving and is very dynamic in this regard. However, it is not a replacement for C or C++ like we were made to believe. And now that the linked article also explains the costs of ABI stability (even the simplest struct's introduce indirections at the dylib boundaries!) I realize I should re-write my audio app in mixed Swift + C.
- rishav_sharan 7y agoI want to try swift but the fact that there is no windows support is a deal killer for me. And it perplexes me how over the years there have been no serious attempts to make it happen. Is it just a cult of Apple + Linux masterrace thing?
- rimliu 7y agoThere are Windows technologies not available on OS X or Linux, is that Windows masterrace thing? If there is no support for Windows it may indicate there was little demand for that. The biggest domain for Swift is still Apple OSes (macOS, iOS, iPadOS, watchOS, tvOS) and some attempts to use it on the server side. Swift is open source, if someone wants to make it happen on Windows, they are Welcome. I do not see the reason why anyone at Apple or anyone working on Linux would bother to do that.
- saagarjha 7y agoThere are people (not from Apple) working on this.
- bsaul 7y agoWindows is nonexistence as mobile OS ,and people deploying windows server are probably already entrenched in using .Net technologies anyway. Provided that you can still install linux on any computer to develop on, i don't see a real market for swift on windows.
- voidmain0001 7y agoIt's a good thing Microsoft doesn't think that way. It apparently has metrics that show desktop development is not stagnating, but rising thanks in part to Windows desktop OS usage also rising [1]. See its plans for WinUI v3 [2]. WinUI is not cross-platform but it is talking about it. [1] Comments from Ryan at MS https://www.dotnetrocks.com/?show=1660 https://www.dotnetrocks.com/?show=1660 [2] https://github.com/microsoft/microsoft-ui-xaml/blob/master/docs/roadmap.md https://github.com/microsoft/microsoft-ui-xaml/blob/master/d...
- 7y ago
- progval 7y agoInteresting comment on Reddit: https://www.reddit.com/r/rust/comments/dtqm36/how_swift_achieved_dynamic_linking_where_rust/f6yh5jy/ https://www.reddit.com/r/rust/comments/dtqm36/how_swift_achi... > You can actually already do dynamic linking in Rust, but only with C-based interfaces. The C-like interfaces that gankra talks about are I belive more similar to current Rust than to C, so I think they shouldn't be called C-like. They could support structs, enums, trait objects, lifetimes, slices, etc. "Stable ABI Rust" would be a name that's more fair. Addition of generator based async and generics of course won't work, but not all interfaces actually need those features. > I think there is definitely potential for a "better dynamic linking" RFC that adds a stable ABI to the language. Of course, the default compilation mode should keep using unstable ABIs, generics, async, etc. But allowing crate writers to opt into a stable ABI would be beneficial for precompiled crates as well as compile times which are still the biggest problem with the Rust compiler for many people. (a crate is a Rust package)
- zozbot234 7y ago>But allowing crate writers to opt into a stable ABI would be beneficial for precompiled crates as well as compile times I think there is already a fuzzy convention that could basically be made to enable this. A crate name ending in -sys is expected to provide a C-like interface, and to thus be usable in a dylib context, whereas the same crate name with no suffix or with a -rs one provides a statically-linked, ABI-unstable wrapper to its corresponding -sys. The build system just needs to be made aware that the former kind of crate need not be recompiled when potential ABI-breaks are introduced. > (a crate is a Rust package) A crate is a Rust compilation unit. Closer to a .cxx, .o file in C/C++ than what are usually called "packages" there.
- epage 7y ago-sys are raw wrappers around C code so wouldn't provide much benefit for them to be exposed as dynlibs. And crates are the equivelant of python, node, go, etc packages. That they are also a compilation unit is, I believe, an implementation detail. I think they also made it configurable.
- chmaynard 7y agoFrom the article: "... Swift's Stabilized ABIs on Apple platforms ... are not actually properly documented, xcode just implements it and the devs will do their best not to break it. Apple is not opposed to documenting it, it's just a lot of work and shipping was understandably higher-priority." Having worked in Apple's Developer Publications department for eleven years, I can confirm that this statement is mostly correct. Apple has the financial resources to hire more technical writers and properly document all their APIs, but it's just not a priority. The sad thing is that developers outside Apple need this documentation and would even be willing to help write it. But they can't because, as a matter of policy, Apple does not generally involve the developer community in writing their official documentation.
- mojuba 7y agoIn some areas Apple's documentation is dismal to the point of being ridiculously useless. Like this (from CoreAudio): mWordClockTime The word clock time. And nothing else on that page apart from that it's UInt64. And it's been like this for years if not decades already. Nothing's changed since the APIs were also bridged and the documentation re-written for Swift. I doubt it's the intent (to keep the developers in the dark with regard to CoreAudio? unlikely), just neglect. Apple, otherwise one of the few companies that pays attention to details and have unlimited resources for this type of tasks, what's their problem really?
- coldtea 7y ago>And nothing else on that page apart from that it's UInt64. What else exactly do you need? It's a reference page for the members of the struct AudioTimeSTamp: https://developer.apple.com/documentation/coreaudiotypes/audiotimestamp https://developer.apple.com/documentation/coreaudiotypes/aud... I wish many C/C++ libs had such a good documentation...
- Tempest1981 7y ago> What else exactly do you need? I always like to know the units (seconds? nanoseconds?) and the reference-year (1970? 2001? 1601?)
- pornel 7y agoIt would be super cool if Rust supported the Swift ABI. Currently use of Rust for macOS or iOS applications necessarily involves adding a plain C layer between Swifty UI and Rusty back-end.
- skohan 7y agoYou can go in the other direction, no? Write a Rust library with a C FFI (directly in Rust) and call it from Swift?
- pornel 7y agoThis is what I meant by a "C layer". No matter how you slice it, you have to "dumb down" communication to the C level and generate C headers. Then you either work with opaque types, or have to generate extra translation and/or wrapper types for classes, closures, etc. Both languages treat C as "unsafe", so it also makes memory safety trickier than if they could use their native safe APIs.
- skohan 7y agoOk yeah I understand what you mean. Yeah it would be super interesting to have closer integration between Swift and Rust. For instance, if you could treat Rust traits as protocols or vice versa. It seems super compelling the idea of writing low-level memory handling in Rust and then operating on it with high level Swift code.
- flipgimble 7y agoIn reading comments about Swift on this and other HN threads I see a lot opinions that in my experience are completely off the mark: a) "Apple cares only about iOS so thats all Swift will be used for" b) "Swift is in fact slow, look at this (naive) swift code vs. this (heavily optimized) c/c++ code". While for people who take time to really work with Swift (yes those are often iOS and Mac developers by necessity) come away with an opinion that Swift is really a diamond in the rough, a new generation of a language co-evolving along with Kotlin and Rust. One distinction is that Apple can afford to hire top-tier compiler developers (including the founder of Rust) and invest heavily in tooling and growing the Swift ecosystem. They can pull off projects like ABI stability which took more than a year of focus for the whole team. I point this out because the is always some sort of opportunity where widespread public perception is so mismatched against reality. I predict in the future there will be some tech startup that will go all in on the Swift ecosystem and be able to run circles around the competition. Note for responders: I'm not saying the languages aren't just as good, or better. I'm not excusing the fact that Apple definitely dictates the priority of where the compiler team invests their time.
- skohan 7y ago> I predict in the future there will be some tech startup that will go all in on the Swift ecosystem and be able to run circles around the competition. Personally I'm really interested with what's going in with Swift in the math/science space. The work that's going on with Automatic Differentiation is fascinating, and the Numeric library which has just been released should make it much easier to achieve highly accurate numerical results in Swift. I agree with you that Swift's public perception is out of step with the reality of the language. It certainly has issues, and when comparing the developer experience with something like Rust, it falls way short on things like tooling, and platform support, but it's just so easy to be productive in Swift I keep coming back to it.
- oautholaf 7y agoHere's one thing I don't understand: In addition to enabling dynamic linking, this mechanism allows Swift to compile less code (generic functions only need to be compiled once) and therefore reduce instruction cache misses. But certainly the tradeoff for this type-info-vtable "witness table" and much more heavy boxing must impact the data cache miss rate. What's the tradeoff end up being in practical terms? Is it worth it? Also, although it seems there's features that let you "freeze" a type, is there a practical way that a non-language expert could ever profile and discover that they may want to use such a feature to improve performance? Especially given that Swift programs on iOS probably only dynamically link to the system libraries, this seems like a powerful language feature to enable something that could have been achieved by writing the Swift system libraries as typed facades around a typeless core, which you so often see in C++ STL implementations.
- int_19h 7y agoStable ABI and especially the issue of generics is why I think bytecode+JIT is the right approach to a language that operates at this level of abstraction. Higher-level semantics of bytecode allow for much more flexibility wrt ABI, and JIT lets you compile generic code monomorphically across ABI boundaries, and even inline it. A long time ago I did some experiments with very carefully written C# code, and it was capable of the same abstraction as C++ STL containers and algorithms, while producing highly efficient native code because everything was inlined at runtime.