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
async
would be beneficial. Most of the discussion centred not onasync
, but onthrows
. Accepting this amendment makesasync
more different fromthrows
, and there was some sentiment that this amendment should only be accepted if we also allow overloading onthrows
accordingly. The Core Team disagreed with this approach for two specific reasons:
- First,
throws
is 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
..catch
constructs have no analogy inasync
). It is not a given thatthrows
andasync
must be consistent with respect to their overloading behaviour.- Second, overloading on
async
is timely in a way thatthrows
is not. There are noasync
APIs 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., anAsync
suffix) that won’t be able to be fixed later.throws
is different, because the overloading rule has been in place since Swift 2.0. Delaying the ability to overload onasync
has 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
@globalActor
impart 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
GlobalActor
to 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 whatT
is 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@globalActor
on subclassable classes, there would also be interesting interactions possible where a class may inherit aGlobalActor
protocol conformance, but not be marked@globalActor
itself, 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.init
initializer, 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
GlobalActor
protocol, 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
YieldResult
to 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
AsyncThrowingStream
generic on Failure but the initializers only afford for creationwhere Failure == Error
- removed the example of
DispatchSource
signals since the otherDispatchSource
types 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
Clamped
example, every wrapped instance will store its ownrange
— even though there isn’t a way for this range to change across differentHud
initializations.
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
nonisolated
declaration to only involveSendable
types. This eliminates the potential for data races due to non-Sendable
values being accessible from any actor.
Becca Royal-Gordon pitched an idea to improve the import access control.
Over the last few years, the
import
statement 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
@_implementationOnly
attribute. An@_implementationOnly import
is 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 import
in apublic
,open
, or@usableFromInline
declaration (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,
Never
was 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
Never
toEquatable
andHashable
in SE-0215 was motivated by examples like usingNever
as a generic constraint in types likeResult
and in enumerations. These same use cases motivate the conformance ofNever
toIdentifiable
, which is pervasive in commonly used frameworks like SwiftUI.