8 ms·
How async/await works internally in Swift
- deleted 3y ago[deleted]
- keltex 3y agoI've been playing around with Swift and SwiftUI for the past few months and the thing that baffles me is why are certain features only available with a minimum iOS version. For example async required iOS 15.0. Why is this tied to the OS? Why can't they include newer runtimes be downloadable like Node / Java / .NET etc? Other examples are from SwiftUI. For example the NavigationStack appears much more useful than the older NavigationView but that requires iOS 16. Which means that you can't support anything older than an iPhone X.
- macintosh-hd 3y agoI think it comes down to Apple trying to avoid as much fragmentation as possible. Fragmentation makes debugging, troubleshooting, and development a nightmare. It’s not an objective good but everything has its trade offs.
- saurik 3y agoFWIW, as the application developer, it increases fragmentation, as more of the code in your app is determined by what version of the OS the user is running. If Apple were developing and debugging everyone's apps, that argument would make sense (but, of course, they are not). If you truly want to minimize costs for development and debugging by minimizing fragmentation you want to provide the most uniform and stable interface as possible for the developer and let the app then operate as identically as possible across every device it will ever work on, not just today but into the future.
- vlovich123 3y agoMost Apple users always run the latest iOS version. And the vast majority of apps aren’t seeing major new OS features each iOS release anymore that they just have to adopt to stay competitive - they can focus on their business these days. So in that kind of market, this approach does reduce support costs because you just pick a target iOS version to support and test with devices running that and you know newer devices will also just work.
- SkiFire13 3y agoI don't see how this would reduce support costs compared to shipping the runtime with the app. Couldn't you just pick a target iOS/Swift runtime version and support that even if the runtime wasn't tied to the iOS version?
- vlovich123 3y agoThe reduced support costs are that your testing complexity (ie cost) is hugely driven by how many OSes you are supporting. By bundling it with the app, you’re pretending that the Swift runtime is the only thing you have to test when you have to test all the OS integration bits. So by tying the runtime to the OS it’s saying “these are the same” and you only have a single compat flag to select. They do this with C++ runtime as well btw. And I believe the language and the runtime are decoupled from what I read although I haven’t paid attention to swift for a long time (ie you can enable new language features without using a new runtime). The other support costs it reduces is for Apple because their testing matrix for making runtime releases is drastically reduced. Which means the swift team runs more efficiently. It’s annoying but for end users it’s even more valuable because apps are smaller (and more longevity for storage) and less memory is used. TLDR: Apple has always run the languages this way and it works nicely for their ecosystem.
- withinboredom 3y ago> Most Apple users always run the latest iOS version. I assume you're talking about the latest iOS version for their device, which may or may not be the latest iOS version released by Apple. I was running around with an iPhone 5 until 2019ish when apps stopped working altogether.
- clawoo 3y agoJoke's on them because debugging is already a nightmare. I've been using Swift since its inception, it's been years since I've been able to pause execution at a certain breakpoint and do "po object" and get something back that is not an error.
- newZWhoDis 3y agoWell for starters, if you were actually playing around with async/await on iOS you’d quickly find out it was back ported to iOS13. It is frustrating though, although in my case 40% of my DAU are already on iOS 17 (>3m devices) so it’s not the end of the world.
- wahnfrieden 3y agoASync has been backported to 13
- e28eta 3y agoHere’s a blog post where they describe the rationale behind switching from app-specific swift versions to bundling it with the OS. https://www.swift.org/blog/abi-stability-and-apple/ https://www.swift.org/blog/abi-stability-and-apple/
- saled 3y agoMy understanding for the reasoning behind this is that they don't want apps to have to ship the runtime stuff to avoid downloads and app sizes getting large. That could be fixed by just shipping an updated shared library to all phones similar to how Google play services works on Android, but I guess they figure if you're updating anyway you might as well just update the whole OS.
- eviks 3y agoYeah, that's a bad design that leaves many functional old devices in the dust
- perfectstorm 3y ago> Apple was one of the companies at the time that recognised the need for a safer, modern alternative to these languages. While no amount of compiler features can prevent you from introducing logic errors, they believed programming languages should be able to prevent undefined behavior, and this vision eventually led to the birth of Swift: a language that prioritized memory safety. i'm pretty sure that's not the reason for the birth of Swift. Trying to access the 20th element from an array of 2 elements would cause a crash in almost all languages including Objective-C which Swift replaced.
- ninkendo 3y ago> Trying to access the 20th element from an array of 2 elements would cause a crash in almost all languages including Objective-C It depends on which part of objective C you’re referring to: the C part, or the objective part. ObjC has NSArray, which has safe, bounds checked accessors. But ObjC is a strict superset of C, and C has very unsafe C-style arrays. In the latter, you definitely don’t always get a simple crash for accessing out of bounds… you get UB and buffer overflow exploits, same as C.
- greiskul 3y agoYeah, people that shit on memory safety don't understand that memory bugs don't just lead to your program crashing. That has never been a problem. The problem is that they lead to you having to roll out fixes in a hurry in a race against hackers, with the company and safety of customer data on the line. A program crash is just an availability issue, a security bug can be an existential risk for a company.
- ninkendo 3y agoRight. To elaborate on my original point, because ObjC includes C, saying "ObjC has safe arrays because it crashes on OOB" is both true and irrelevant. It has safe arrays, but that's not all it has. It also has very, very unsafe arrays. Swift doesn't have this issue, there is no unsafe array type in Swift (absent doing very unsafe byte-level address casting using functions that are literally prefixed with the word "unsafe".)
- wereHamster 3y ago> […] the so-called “precursor programming languages” like C++ or Obj-C. Like if there were no other languages before C++ or Obj-C, eh? What about C? Or Fortran? Or Ada? Speaking of Ada… > Apple was one of the companies at the time that recognised the need for a safer, modern alternative to these languages. People recognised need for safer languages way before Swift was created.
- pjmlp 3y agoSince 1958 actually, had UNIX not been originally available as free beer, C wouldn't have taken over the world.
- keyle 3y agoSwift is a very modern language and very few languages get close to its safety. Rust does and goes beyond, Zig probably is very similar.
- ben_w 3y agoI remember my dad complaining about the invention of Ada and how bad it was, designed by committee, etc. At least, I think it was Ada. Can't ask any more, he was born in '39, we scattered his ashes nearly a decade ago.
- novok 3y agoSwift async/await is such a foot gun that induces deadlock over deadlock, and whats even worse, deadlocks the entire app so you cannot report and notice this deadlock state in the app itself, which makes you blind. I almost never had this problem with dispatch, you could fairly reliably guarantee and reason about some backup queues being able to detect these states and report the deadlock state. IMO I would recommend not interacting with async/await as much as possible and stick to dispatch queues you can reason about far more easily.
- andreasley 3y agoDo you happen to have some links to information about the issues you mentioned? Swift async/await has worked excellently for me so far. The biggest issue is that most libraries aren't updated to use it (and sometimes couldn't be, because they require Custom Actor Executors, which weren't available until Swift 5.9). I found the following video helpful to better understand Swift async/await: "Swift concurrency: Behind the scenes" https://developer.apple.com/videos/play/wwdc2021/10254 https://developer.apple.com/videos/play/wwdc2021/10254
- dagmx 3y agoI’m curious what sort of data structures you’re using where you’re hitting deadlocks? Are you by chance doing shared mutation of lists? I’ve written several async Swift apps and not hid deadlocks but I also tend to structure my data in ways that avoid shared rw access where possible.
- secretsatan 3y agoI've not really played around with async/await because I immediately found issues trying to replace my GCD code, swift still doesn't have the fine grained control GCD offers. I replaced some of my other async code with Combine, which I do really like now, it's proving itself to be pretty solid
- tcldr 3y agoI'm not sure what you're doing to get into deadlocks, but when used as prescribed, I personally haven't run in to these issues. Swift concurrency is still in a transitory period, and with that comes some warnings about how you can mix it with legacy concurrency primitives. i.e. not holding a lock across Task boundaries. However, it's fairly well documented. There's a talk 'Swift concurrency: Behind the scenes' [1], that goes into detail on this. View from around the 25 min mark. [1] https://developer.apple.com/wwdc21/10254?time=1614 https://developer.apple.com/wwdc21/10254?time=1614
- bsaul 3y agoMy main pattern of concurrency is scheduling a computation made of a serie of asynchronous steps. I want this computation to be cancellable, and i want to schedule them keeping them in order. Basically NSOperation scheduled to a non-concurrent operation queue, where the operation itself is made of async calls. What would be the recommended approach for doing that with swift concurrency ?
- saagarjha 3y agoProbably write your own queue
- mattiemass 3y agoI have found myself, many times, in exactly the same situation. I think a concurrency-compatible queue is basically essential for many kinds of pretty boring situations. I made one here, and it look a lot like an OperationQueue. But it also points to another implementation I found recently that is certainly different, but also might be interesting. https://github.com/mattmassicotte/Queue https://github.com/mattmassicotte/Queue
- bsaul 3y agothanks, yes i saw that link in the video linked in OP. I am absolutely dumbounded swift concurrency and actors don't offer a trivial solution to that problem.
- smallstepforman 3y agoI’ve been doing multithreaded embedded system for over 20 years, and the latest system is a custom Actor C++ framework (so yes, I’ve professionally used Actors in a shiping system). Having said that, I find Apple’s implementation exceptionally complex. Aiming for safety and catering to inexperienced devs, they’ve created something way too complex for less experienced devs to understand. In my personal opinion, they should have overlooked Actor safety and gone with a simpler model which is easily understandable, and rely on experienced devs to understand what is happening under the covers and program accordingly. To use a cooking analogy, We live in a bizarro world where chefs are being asked to abandon cooking knives (they’re dangerous), and to use dozens of kitchen aids for safety. And the limitations this produces…
- DarkNova6 3y agoI wonder. Do you happen to know how Swifts new Concurrency Model compares to C# and Java 21?
- neonsunset 3y agoYet to read the article :) C# and Rust async models are based on top of state machines and cooperative yielding back to the executor. The difference between C# and Rust is a tradeoff of either the ability to just not think and use async/await naturally with really nice defaults but paying for those with heap allocations of state captured by continuations or dealing with the memory model explicitly which requires more effort but gives you fully configurable and/or deterministic behavior, that can (and usually does) achieve far lower overhead. Java uses green (virtual) threads where the runtime can preempt (pause/suspend) them (keeping virtual thread stack in memory) and schedule the execution of a different green thread on top of the current physical one, not dissimilar to C#/Rust as they achieve so explicitly, where the next work item is executed by the threadpool once the current one yields.
- deleted 3y ago[deleted]