The proposal somewhat highlights this but let me put it here again, that this is a low level and specialized for performance API. Some tradeoffs were made in to serve that purpose, as well as existing ABI compatibility.
This is a way to talk about memory visibility happens-before / happens-after are ways to talk about visibility of memory writes. into simpler terms it means synchronize your executor code correctly such that effects of an enqueue are properly visible for the run when it executes.
This would require making multiple calls from the Swift runtime across to user code which is expensive. Since this is a core building block of the concurrency runtime, we want to avoid making many calls like this. @John_McCall may have more to say on this, but in my understanding we'd really want to avoid making multiple calls into user-provided code. For this specific equality it might have been fine, since we only need to check this lazily, that's true but I'm not sure if it is worth the change.
You can convert it to a TaskPriority and use those well defined priority values.
Generally it can contain arbitrary values and we do not define what they mean or how they must be interpreted. It's up to an executor to deal with this. We've implemented executors in other runtimes which have utilized wider priority space and this opaqueness / flexibility has been helpful in such runtimes.
It cannot be because current limitations in @_moveOnly types: a move only type cannot conform to protocols.
Once this limitation is lifted, this conformance could be added. It does have a description method you can call explicitly though.
Currently no, it could be something we could look into someday. I've not thought about it during this proposal so far though.
(No need for bolding text).
That may be a fair point worth discussing. It wasn't marked unsafe because we lifted existing API and the method already is using an unsafe type: UnownedJob. It is true though that the actual method is what may produce the undefined behavior so it may be worth calling it out again...
I'd like the language/core team to comment on this though. If we feel the SerialExecutor.runSynchronously(UnownedJob) should change to: SerialExecutor.runSynchronouslyUnsafe(UnownedJob), i.e. if doubling down on this unsafety is helpful, or we already consider the UnownedJob "signalling the unsafety".
Now, the move-only version would technically remain safe as: SerialExecutor.runSynchronously(consuming ExecutorJob) since it consumes the job.
Though note that it isn't actually safe, because one can make two ExecutorJobs (incorrectly) out of a single UnownedJob and attempt running the moveonly jobs, which would result in the same issue. So I think it's unclear how many scary names we should throw at those APIs, given the mere existence of UnownedJob makes everything that Job touches unsafe. Do we have to make every API unsafe, or acknowlage that jobs need the extra attention.
I'd kind of want @John_McCall @Joe_Groff or the core/language team to provide some guidance here to be honest, because it seems like a general question about such situations involving an unsafe type or, a thing obtainable from an unsafe type to then proceed abusing it.
That would be an interesting improvement and perhaps we could revisit this in the future.
I agree that distributed handles this rather nicely and the issue is quite similar to the one executors face, though their lifetimes (and the actor systems) is a bit inversed.
Having implemented this mechanism in distributed though I'll mention that this is a very complex effort and likely not possible in scope of this proposal in order to make it on time into Swift 5.9. Perhaps we could explore this in the future though -- it would ahve to store an ExecutorRef and we'd synthesize the returning of it.
I was quite torn on naming here as well... on one hand the parallel with assert/precondition is nice, but it doesn't read so well.
Summing up:
isSameExclusiveExecutionContext adding "as" label, we still could but coordinating this change may be tricky across adopters;
- Avoiding making it static is AFAIR something we did on purpose in order to allow a superclass/subclass to share the implementation of equality based on a supertype. I don't think we'd want to make it static for that reason.
- ExecutorJob and CustomStringConvertible - cannot be fixed until moveonly types can conform to protocols
- flags rather than returning
asUnownedExecutor likely problematic due to runtime overhead of using multiple function calls; The previous API also already exists in the ABI so it's not like we can remove it entirely.
- distributed actor-like executor initialization, interesting but I don't think we'll be able to make this work in a short period of time; It could be a follow up in the future.
requireIsolated maybe worth the rename, we can do this safely