Hi everyone. The review of SE-0553: Task Identity begins now and runs through October 7th, 2026.
Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to me as the review manager by DM. When contacting the review manager directly, please put "SE-0553" in the subject line.
What goes into a review?
The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:
What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
When we accepted withTimeout we noted that it would be acceptable as an optimization to implement the main operation of withTimeout as being part of the same runtime task as the caller of withTimeout, on the basis that such implementation would not be observable from within the language. IIUC this proposal would give a narrow way to observe that, by having it be the case that Task.currentID reports the same value from outside withTimeout and inside withTimeout, is that correct?
Optional<Task.ID> is 16 bytes and is returned in two registers;
That's unfortunate, but I agree that TaskID? is a more idiomatic type for this rather than using sentinel values. Logging use cases probably will be happy with TaskID?, but lock free data structures require a valid task identifier. So distinguishing the two in the type system is useful.
But what if we can have the best of the both worlds? For UnsafeRawPointer compiler knows that null is an invalid bit combination and reuses it for representing UnsafeRawPointer. Can TaskID store under the hood Builtin.NonZeroUInt64 or something like that?
Right, that's what I'm getting at--with a mechanism for observing a task's ID available within the language, it would be possible to observe that task.id (say, obtained by the caller of withDeadline because they have a handle to the calling Task) is the same as Task.currentID within the operation of withDeadline, and yet task.isCancelled != Task.isCancelled.
But the task name makes no identity guarantee so "withDeadline's operation runs in a task with the same name as its parent" remains perfectly consistent with the observed semantics.
withDeadline is implemented without a child task today already, as Franz linked to.
Yes, technically this does give an "official" way to check the actual identity of tasks and observe if something is the same task or not. Personally I think this falls into the category of performance optimization and "understanding" runtime behavior, including matching what you see in logs and runtime to e.g. what you see in Instruments when you monitor the same process. So in that sense, you already had ways to observe these IDs (from swift-inspect, or Instruments etc).
It's worth asking the question I suppose, though this was intentionally not made to conform to Identifiable... but I'll admit there's no deep reason for it other than trying to keep Task light and maybe not over-encourage using the task as arbitrary key for lookups, though perhaps there's nothing wrong about doing that hm
Sure, I think that's an acceptable answer (though I do think there's a meaningful difference between only being able to observe via debugger behavior and surfacing visibility of this optimization within the language itself, and I think we'd be crossing that boundary with this proposal).
… and this was one large reason for driving the proposal from the start — this is crucial for being able to do span trace / logging with reasonable performance (some details in the pitch).
WRT to Identifiable we really focused on the minimum footprint needed for unlocking the use cases outlined in the proposal, but not deeper than that as Konrad mentioned.
I think the debugging / logging driver of this feature is compelling, so I support it. I do think we’re likely to see a lot of improper uses of it for various side-channels of information, and I wish the proposal were more discouraging of that, rather than almost accepting it as a good thing.
I would definitely be happy to reword to that effect if desired, I do agree in principle that use should be discouraged (but is truly needed for these use cases -- in some way analogous to unsafe constructs, sometimes you need to be able to reach for certain tools to not be at a platform disadvantage.)