Hello, Swift community.
The third review of SE-0311: Task-local values begins now and runs through June 9th, 2021.
The second review ended several weeks ago; I apologize for the fact that the community has been left hanging.
The second review of SE-0311 was run to consider a significantly different language approach for binding and accessing task-local values, one based around property wrappers rather than an explicit key type. Shortly after the second review started, the community provided strong feedback that the proposal's new use of property wrappers didn't match their expectations because of the indirection through a wrapper value. The author agreed to re-revise the proposal, and the review was extended.
The Core Team has tried to evaluate the community's feedback as it applies to that revised second proposal, understanding that it's not always easy to pick apart. The major thrusts are as follows:
-
Overall, the community strongly supports the new use of property wrappers.
-
There's some discomfort over the verbosity and nesting of the
with
-style scoped API for installing a new task-local value. The author believes that scoping is an important part of the basic design. The Core Team agrees and believes that we can investigate ways of improving the syntax for this sort of scoped change to a value. -
There's some discomfort over the fact that it's not possible to mutate the current value. If the new value needs to be derived from the current value, e.g. by appending to an array, the old value must be copied, modified, and then re-installed, which will generally defeat the standard library's copy-on-write optimizations. This is an inevitable trade-off of the scoped approach because the old value must be restored when the scope exits. The Core Team believes that it would be an interesting future direction to consider a complementary feature which maintains a stack of values for a key; reading a key would then produce a sequence of values rather than a single one. This would also allow some clients to be much lazier when installing values; for example, code could install and look up individual entries in a dictionary without ever having to construct a full
Dictionary
value for all the installed keys. -
Some community members felt that it was odd that you could set a default value for a task-local, as opposed to the task-local being forced to be optional. The author believes that default values avoid a lot of practical inconveniences with optionals, such as needing to spell the desired default at every use site with a
??
operator. The Core Team discussed this and agrees that having a default value is the right design rather than forcing the use of optionals. -
Some community members feel that it's odd that values can be read in any function but that new values can only be set in
async
functions. This kind of contextual value isn't solely useful inasync
code; many sorts of APIs can benefit from it. Moreover, the current set of task-local values are captured during the creation of certain kinds of non-structured task, and so it's meaningful to be able to install values that will be captured this way. The Core Team agrees, and the author has agreed to revise the proposal to allow this.However, please note that the feature is still driven by the use case of task-local values, which imposes certain constraints that might be unsuitable for other use cases of contextual values or thread-local storage. Most importantly, task-local value types must be
Sendable
, which means that the feature cannot be used to e.g. install a contextual reference to a mutable class instance (at least, not without bypassingSendable
checking).
The Core Team has elected to run this third review in order to consider this final change, where values can be installed even in synchronous code. The Core Team is otherwise prepared to accept SE-0311 as proposed. However, because of the rather complex schedule of revisions, we believe it is possible that some members of the community are confused about what exactly is proposed, and so we do still invite feedback on the overall proposal.
This review is part of the larger concurrency feature , which we are reviewing in several parts. While we've tried to make it independent of other concurrency proposals that have not yet been reviewed, it may have some dependencies that we've failed to eliminate. Please do your best to review it on its own merits, while still understanding its relationship to the larger feature. However, if you see any problematic interactions with proposals that have already been reviewed, that are currently in review, or that are currently being pitched, that is highly valuable feedback.
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. If you do email me directly, please put "SE-0311" somewhere 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?
More information about the Swift evolution process is available at:
https://github.com/apple/swift-evolution/blob/master/process.md
As always, thank you for contributing to Swift.
John McCall
Review Manager