It is a risky time for Swift. They are channeling enormous resources into solving multi-threading at compile time, but the remedy is worse than the sickness. They are introducing a whole different problem: systemic race conditions. Interleaving of async functions. These are much more difficult to track down IMO. I am literally breaking my head on some of these things. Without a transactional system like dispatch, you end up with something more complex than multithreading.
@drewmccormack this sounds right, but I’m not sure I understand. Can you explain a bit more or maybe even have an example?
@cocoafrog If you have an async func with several awaits in it, and you call it more than once, you can easily have undefined state, because the two calls run simultaneously, with no guarantees about order, or that one will complete before the other. Now scale that up to an app codebase. Imagine all these async “threads" interleaving. Other than the simplest case (eg consuming a web service), it makes for a complex system. At least with dispatch, you could easily reason about order etc.
@drewmccormack @cocoafrog it might not be so bad if the stdlib provided some sort of serialization primitive, like @groue ‘s AsyncSemaphore or @mattiem ‘s Queue. Having to rely on 3rd party code for a basic concurrency construct is wild to me
@calicoding @drewmccormack @cocoafrog @mattiem The way I see it: this is comparable to the times before Result became standardized in the stdlib. The language designers were _very_ reluctant to commit such a type in the stdlib, and even to acknowledge that it was needed. They needed a lot of time to convince themselves not only that Result was useful, but also that alternatives were discarded for good – or too far in the future.
@groue @calicoding @drewmccormack @cocoafrog @mattiem I think something like an async queue should be included in the concurrency library. The AsyncStream boilerplate is repeated everywhere for this sort of pattern, and we should make it easier to write because it’s a pattern that a lot of people need when order has to be guaranteed.
@holly @calicoding @drewmccormack @cocoafrog @mattiem Immediate boost ;-) It's just too cool to read this!
@holly @groue @calicoding @cocoafrog @mattiem I have been using AsyncStream as a type of queue. As you say, there is that boiler plate barrier to use. But for me it goes a bit further, because you can’t just await an enqueued task. I guess what I want is indeed a task queue where I can just enqueue and await.
@drewmccormack @holly @calicoding @cocoafrog @mattiem You can enqueue and await with a continuation: the enqueued job wraps the "real" job, and resumes the continuation when it is done.
@groue @drewmccormack @holly @calicoding @cocoafrog @mattiem I may have done it wrong but I had performance problems bridging things this way and abandoned that effort.

@holly @groue @calicoding @drewmccormack @cocoafrog @mattiem

Sometimes reinventing the hot water is not a good idea. The concept of the old Obj-C NSOperationQueue & Co. was many times simpler to understand and easier to use. Swift needs to push the brake, clean up the mess, and simplify! Otherwise it is heading to yet another C++…

@tuparev @holly @groue @calicoding @drewmccormack @cocoafrog This reaction is understandable. But, now that I’ve had time to learn and practice, neither of which were trivial, I find queues incredibly hard to use in comparison. And I was using NSOperationQueue for 20 years!
@mattiem @tuparev @holly @calicoding @drewmccormack @cocoafrog It was indeed verbose to implement a non-synchronous Operation subclass due to the heavy KVO work. One also quickly needs support for early cancellation (op cancelled before it is ready and scheduled in the queue), and this needed a bunch of supplementary flags. Handling operation completion (cancel/success/failure) was not standardized, and needed extra work, too. That was easily reused code, though, once this heroic phase passed.

@groue @tuparev @holly @calicoding @drewmccormack @cocoafrog Yes you’re right! I was actually talking about post-usable operations. I now strongly prefer thinking in terms of the things I need to protect, not the mechanisms I need to protect them.

Doesn’t make it easy to learn/migrate though.

@mattiem @tuparev @holly @calicoding @drewmccormack @cocoafrog The key is to acknowledge that the previous techniques are not invalidated. Most of us maintain existing code that is not migrated, or not even planned for migration at the time being. Add a touch of "if it ain't broken, don't fix it", as the saying goes, and it’s easy to understand some wry reactions. One's motivation to learn and migrate can be totally absent of another perfectly competent person, at a given time.
@groue @tuparev @holly @calicoding @drewmccormack @cocoafrog Yeah this is a very good point!
@mattiem @groue @tuparev @holly @calicoding @drewmccormack @cocoafrog To me NSOperation's are not just (maybe not even primarily) about concurrency (and as mentioned concurrency is actually a little annoying with them).
They are an implementation of the Command pattern. I.e. something that wraps up everything required to perform one (more complex) thing. To give structure to code. The Swift replacement kinda is `callAsFunction` (does this work w/ async and even actors?).
@helge @mattiem @groue @tuparev @holly @calicoding @drewmccormack @cocoafrog … what? callAsFunction is definitely not intended to be a replacement for NSOperation.

@steve @helge @groue @tuparev @holly @calicoding @drewmccormack @cocoafrog I think the context was about a type that describes work you can run. I wouldn’t have thought of it, but I see it.

But I also think that the dominant use of OperationQueues is for concurrency.

@mattiem @steve @helge @groue @holly @calicoding @drewmccormack @cocoafrog

“But I also think that the dominant use of OperationQueues is for concurrency.”

YES!

@mattiem @steve @groue @tuparev @holly @calicoding @drewmccormack @cocoafrog Yes, you don't have to use NSOperation's within queues, though of course that is most common 🙂 (but e.g. in OpenGroupware we had sth similar w/o a queue).
The key concept of an operation (command) is that you can parameterize it, and then it has a single "run-it" entry point (main).
And if you can use callAsFunction w/ async or on actors(?), it actually even gets the concurrency features.
@helge @steve @groue @tuparev @holly @calicoding @drewmccormack @cocoafrog I completely get what you are saying and agree. I just think we may be drifting too far from the original discussion.
@mattiem @helge @groue @tuparev @holly @calicoding @drewmccormack @cocoafrog right, but NSOperation is work you can run _once_, and has a bunch of KVO machinery to query status. callAsFunction is just a thing you can invoke, with none of the other machinery.

@steve Taking out the other people to not further distract them, hope this works 🙂
Yes, I understand what an NSOperation can do (Shrugs is completely built around them, and doesn't always queue them!).

What I said is that the more important thing about them IMO is that it allows one to compose more complex functionality w/ a single entry point. This can be achieved by callAsFunction.
Think this (I understand that it _still_ isn't 100% the same):

@holly I am trying to build this now and failing :( lots of gotchas