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 on async, but on throws. Accepting this amendment makes async more different from throws, and there was some sentiment that this amendment should only be accepted if we also allow overloading on throws accordingly. The Core Team disagreed with this approach for two specific reasons:

  • First, throws is not necessarily as amenable to overloading as async, due to the presence of control flow that handles thrown errors without requiring the enclosing context to be throws (try?, try!, and do..catch constructs have no analogy in async). It is not a given that throws and async must be consistent with respect to their overloading behaviour.
  • Second, overloading on async is timely in a way that throws is not. There are no async APIs now, but the Swift community will be adding them as soon as Swift 5.5 becomes available. Without overloading on async, the Swift ecosystem will end up with a nontrivial number of APIs with non-ideal names (e.g., an Async 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 on async 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 what T 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 a GlobalActor 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 creation where Failure == Error
  • removed the example of DispatchSource signals since the other DispatchSource 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 a TimedOutError.

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 own range — even though there isn’t a way for this range to change across different Hud 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 involve Sendable 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 a public, 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 to Equatable and Hashable in SE-0215 was motivated by examples like using Never as a generic constraint in types like Result and in enumerations. These same use cases motivate the conformance of Never to Identifiable, which is pervasive in commonly used frameworks like SwiftUI.

Finally