Issue #188 01 Jul 2021
Written by: Kristaps Grinbergs
It seems that WWDC21 has settled down, and people are starting to enjoy the summer. But Swift’s core team hasn’t stopped working, and there are quite a few proposals in review as well as accepted.
This issue of Swift Weekly brings some sad news because the Swift Unwrapped podcast has ended. I want to personally say thanks to Jesse Squires and JP Simard for running Swift Unwrapped for so long - 4.5 years and 92 episodes. It was a wild ride, and I learned a ton. Thank you!
Swift Weekly is looking for sponsors. If your company or someone you know would like to sponsor this community-driven project, reach out! Thank you!
Interested in sponsoring Swift Weekly Brief? Learn more here.
Starter tasks
- SR-14824 [Compiler] Improve diagnostic for multi-statement closures instead of saying “too complex closure return type”
Podcasts
After 4.5 years, 92 episodes, and 830k downloads, Swift Unwrapped is wrapping up. In the last episode 92: Deinit Jesse Squires and JP Simard talk about the history of the show and more.
News and community
Tibor Bödecs wrote a great tutorial about Swift actors.
Accepted proposals
SE-0311 Task-local values was accepted.
The third review of SE-0311: Task-local values concluded a few weeks ago. The review focused on a narrow question: whether to extend the proposal to allow task-local values to be established from synchronous functions. Feedback on this point was quite positive. SE-0311 is therefore accepted without further amendment.
SE-0296 Amendment Allow overloads that differ only in async was accepted.
It was generally accepted that overloading on
asyncwould be beneficial. Most of the discussion centred not onasync, but onthrows. Accepting this amendment makesasyncmore different fromthrows, and there was some sentiment that this amendment should only be accepted if we also allow overloading onthrowsaccordingly. The Core Team disagreed with this approach for two specific reasons:
- First,
throwsis not necessarily as amenable to overloading asasync, due to the presence of control flow that handles thrown errors without requiring the enclosing context to bethrows(try?,try!, anddo..catchconstructs have no analogy inasync). It is not a given thatthrowsandasyncmust be consistent with respect to their overloading behaviour.- Second, overloading on
asyncis timely in a way thatthrowsis not. There are noasyncAPIs now, but the Swift community will be adding them as soon as Swift 5.5 becomes available. Without overloading onasync, the Swift ecosystem will end up with a nontrivial number of APIs with non-ideal names (e.g., anAsyncsuffix) that won’t be able to be fixed later.throwsis different, because the overloading rule has been in place since Swift 2.0. Delaying the ability to overload onasynchas long-term costs that the Core Team feels are not justified by the potential for inconsistency.
SE-0316 Global Actors was accepted.
The second review 4 for SE-0316: Global Actors 7 ran until June 28th, 2021. The core team has decided to accept the proposal with modifications. A few important points were raised during the review and core team discussion, and the proposal will be accepted to address these points:
@BigSur asked whether classes annotated with
@globalActorimpart global-actor-ness on their subclasses, and @filip-sakel raised questions about the ramifications of global actor subclassing on the type system 4. The uses for subclassing a global actor seem limited, so for simplicity’s sake, non-final classes should not be allowed to be annotated as@globalActor. This restriction could be lifted by a future proposal.As reviewed, the proposal allowed for generic arguments that conform to
GlobalActorto be used as global actor attributes, as in@T func foo<T: GlobalActor>(...). @Zhu_Shengqi noted that this could create readability problems 2, since it isn’t clear whatTis referring to until you read further into the declaration. Supporting this also imposes technical challenges on the implementation of user-defined attributes, and opens potential new design questions. For instance, if we later add another protocol for another kind of user-defined attribute, and a generic argument is constrained by two such protocols, then which kind of attribute is@T? Is there a way to control it? Furthermore, if we did support@globalActoron subclassable classes, there would also be interesting interactions possible where a class may inherit aGlobalActorprotocol conformance, but not be marked@globalActoritself, but nonetheless be used indirectly as a global actor constraint by being bound to a generic type argument.For these reasons, the ability to use a generic parameter as a global actor constraint should be removed from this proposal. A future proposal could add this ability, but it will need to consider the design questions raised above.
Proposals in review
SE-0296: Allow overloads that differ only in async amendment is under review.
Based on the discussion of the first pitch, this ability was removed from the proposal. However, experience augmenting existing Swift libraries with async/await functionality has demonstrated that this overloading might be useful, so we would like to reconsider the limitation.
SE-0315: Placeholder types is under review.
Swift’s type inference system is quite powerful, but there are many situations where it is impossible (or simply infeasible) for the compiler to work out the type of an expression, or where the user needs to override the default types worked out by the compiler. Directly referencing the heavily-overloaded
Double.initinitializer, as seen above, is one such situation where the compiler does not have the necessary context to determine the type of the expression without additional context.
SE-0316: Placeholder types is under the second review.
The previous review ended on June 7th. Relative to the previous review, the following changes have been made:
- Added the
GlobalActorprotocol, to which all global actors implictly conform.- Remove the requirement that all global and static variables be annotated with a global actor.
- Added a grammar for closure attributes.
- Clarified the interaction between the main actor and the main thread. Make the main actor a little less “special” in the initial presentation.
SE-0314: AsyncStream and AsyncThrowingStream is under the second review.
The first review 7 received a lot of very useful feedback. In response, the authors have made several changes to the proposal for the second review, summarized here:
- added
YieldResultto express the action of yielding’s impact, either something is enqueued, dropped or the continuation is already terminated- added
init(unfolding: @escaping () async -> Element?)to offer an initializer for unfolding to handle back-pressure based APIs.- made
AsyncThrowingStreamgeneric on Failure but the initializers only afford for creationwhere Failure == Error- removed the example of
DispatchSourcesignals since the otherDispatchSourcetypes might be actively harmful to use in any async context- initialization now takes a buffering policy to both restrict the buffer size as well as configure how elements are dropped
Swift Forums
Ole Begemann started a discussion about running an async task with a timeout.
I wrote a function
async(timeoutAfter:work:). Its goal is to run an async task with a timeout. If the timeout expires and the work hasn’t completed, it should cancel the task and throw aTimedOutError.
Isabel Lima pitched a proposal that would add shared storage to property wrappers.
Property Wrappers are responsible for wrapping common getting and setting boilerplate and also for storing any auxiliary helper properties. Often, these helpers are constant across different instances of the wrapper, not changing after initialization. Thus, having to store these properties in each individual wrapper instance should be avoided. In the following
Clampedexample, every wrapped instance will store its ownrange— even though there isn’t a way for this range to change across differentHudinitializations.
Tim Condon briefed about Swift on the Server Workgroup May 26th 2021 meeting.
Doug Gregor informed us about the amendment to SE-0313.
.. requires any
nonisolateddeclaration to only involveSendabletypes. This eliminates the potential for data races due to non-Sendablevalues being accessible from any actor.
Becca Royal-Gordon pitched an idea to improve the import access control.
Over the last few years, the
importstatement has been collecting unofficial, unsupported features to help manage the dependencies between libraries. We (@xymus and @beccadax) are thinking about how to stabilize some of these into officially-supported language features.Chief among them is the
@_implementationOnlyattribute. An@_implementationOnly importis completely hidden from clients who import your module. This allows clients to import your module even if they do not have access to that module, so it’s great for hiding libraries that you use only as an implementation detail. To make this work, though, the compiler stops you from using a declaration imported via an@_implementationOnly importin apublic,open, or@usableFromInlinedeclaration (including the function body if it’s@inlinable) if that use would be visible to your clients.
Kyle Macomber pitched a proposal that allows Never conform to Identifiable to make it usable as a “bottom type” for generic constraints that require Identifiable.
With the acceptance of SE-0215,
Neverwas deemed as being a “blessed bottom type”, but that it wouldn’t implicitly conform to all protocols—instead explicit conformance should be added where valuable.The conformance of
NevertoEquatableandHashablein SE-0215 was motivated by examples like usingNeveras a generic constraint in types likeResultand in enumerations. These same use cases motivate the conformance ofNevertoIdentifiable, which is pervasive in commonly used frameworks like SwiftUI.