Swift Evolution Monthly: October '22

Lifting limitations on Xcode, Result Builder variables, Existential arguments, testable Clocks, and Back-Deploying Functions

Swift Evolution Monthly: October '22
Photo by Jason Hogan / Unsplash

October has been a very busy month for me for two great reasons:

Firstly, my love for the great country of 🇯🇵 Japan and its people has made me plan for a long-term trip to the country for a long time, and this plan just became a reality this month as Japan reopened its borders. I can look back to a month full of planning, packing, and traveling. The cool thing is: I am actually writing these lines from a café somewhere in Tokyo now, the most populated city on earth! 😍

I'll be here in Japan for the next 3 months, which is a dream come true for me personally. But don't worry, I'll be continuing to work on apps and write articles from here. Just focusing on studying Japanese on top of all else. 🤓

Secondly, as I already mentioned in the last issue, October was the month I intended to release my first app as an Indie developer – and so I did!

Say hello to RemafoX, the app on the mission to simplify developer life by providing new workflows for localization when working with Xcode. I wrote a short article on how it can help you here – if you're very limited on time, make sure to at least watch these GIFs which will give you a good first impression of it.

Here's what other members of the Swift community had to say about it:

This new localisation tool from Cihat Gündüz looks great. As with any tool that tries to integrate with Xcode, setup is a little long-winded and awkward, but once configured, it’s a breeze to add or edit localisations from directly inside your source. The workflow focuses on Xcode, making it an excellent fit for solo developers or small, developer-heavy teams. If that’s you, there’s a free tier/trial, so check it out!

Dave Verwer in iOS Dev Weekly (Issue #580)

@RemafoX_App, a tool for Indie Developers to localize their iOS apps, looks pretty strong in terms of functionality but it also has fabulous in-app onboarding help and YouTube instructional videos 👍👍👍

Marco Eidinger in this Tweet

Also, I couldn't have summarized my motivation behind writing this app better than this flattering first US review on the Mac App Store:

Extremely well made & documented
‌‌I've been using this developer's open-source BartyCrouch localization tool (which) was wonderful but it took ages for me to set up and (learn).
‌‌ReMafoX solves all of those issues extremely well. It's beautifully designed, well organized, and exceptionally well documented. Every step is explained in detail, both in the code, in the app, and via YouTube videos.

And this is just the beginning. Each month, one new (requested) feature will be added, the first is already out with full support for Ventura and Objective-C files. If you have any localized projects or thought about localizing yours to reach more customers but you found the process too finicky, give ReMafoX a try.

But enough of my app, let's get from lifting some of Xcode's limitations to some interesting new proposals that lift some of Swift's limitations!

Accepted Proposals

The following proposals not yet presented were already accepted:

SE-0373: Lift all limitations on variables in result builders

Links: Proposal Document 📝 | Acceptance Rationale | Review 🧵

When writing code in the body of a view in SwiftUI, we can already use a lot of structured programming expressions such as if statements or for-each loops. But we cannot use everything that we can use in a function. For example, lazy variables or property wrappers such as @Clamping suggested in this NSHipster article will work in a function, but not in a SwiftUI body.

The reason is that SwiftUI has a ViewBuilder type, which is a result builder. So all  code you write inside the body runs in a different-than-normal Swift environment, inside the SwiftUI DSL to be exact. This DSL (= domain-specific language) code may look like normal Swift code like we write in a function (thanks to SE-0289), but it actually isn't. What you can do within result builders is restricted, but this new proposal aims to get rid of some of the restrictions – those on variables in particular. In the future, you will be able to write the following code and it will compile fine (without the error in the comments you currently get):

import SwiftUI

struct ContentView: View {
   var body: some View {
      GeometryReader { proxy in
         // ⬇ 'Cannot declare local wrapped variable in builder'
         @Clamping(10...100) var width = proxy.size.width
         Text("Hello World").frame(width: width)
      }
   }
}

‌The full list of removed limitations on variables in result builders is:

  • Uninitialized variables (e.g. let x: Int – with exceptions like SwiftUI)
  • Default-initialized variables (e.g. var comment: String?)
  • Computed variables (get & set)
  • Observed variables (willSet & didSet)
  • Variables with property wrappers (e.g. @Clamping(1..10) var count = 12)
  • lazy variables (e.g. lazy var max: Int = { ... })

I have not personally wanted to use any of these yet, but I'm glad that more restrictions were lifted for those situations where we actually do need them.

SE-0375: Opening existential arguments to optional parameters

Links: Proposal Document 📝 | Acceptance Rationale | Review 🧵

First, let's remember that an 'Existential' is something like an auto-generated "placeholder box type" when working with variables of a Protocol type – see also my more detailed explanation in the April issue here. Now consider this code:

func persist<T: Codable>(_ codable: T?, key: String) {
   if let codable {
      storageDict[key] = try! JSONEncoder().encode(codable)
   } else {
      storageDict.removeValue(forKey: key)
   }
}

func valueChanged(value: any Codable, key: String) {
   // ⬇ 'Type 'any Codable' cannot conform to 'Codable''
   persist(value, key: key)
}

Currently, we get an error when trying to pass the existential any Codable to the persist method which accepts a specific type T that conforms to Codable. Thanks to this new proposal, this will compile in the future as value here is a non-optional and therefore the underlying type can be determined and T is clear.

Proposals In Review/Revision/Awaiting Decision

You can still provide feedback for these proposals. The current rejection rate is <10%, so they're likely to get accepted. Revisions are more common.

On to new proposals in review/revision/awaiting decision!

SE-0374: Add sleep(for:) to Clock

Links: Proposal Document 📝 | Review 🧵

When introducing the new Clock, Instant and Duration types with SE-0329 (see my summary), it seems that one important method on the Clock type was forgotten: A sleep(for: Duration) method. This caused a problem when Brandon Williams and Stephen Celis from Point-Free used these new APIs to write tests and control time in them for fast unit testing. The reason for their problem was that the existing method sleep(until: Instant) didn't allow for using an existential clock type to switch out the real-time Clock in tests with a custom fast-forwardable Clock due to the type-erased Instant needed for the sleep(until: Instant) method.

With this proposal they added a new sleep(for: Duration) method that has no such problem. I'm glad that the community has such great members who play around with new APIs even before they are released so they can already propose a fix to some rough edges before most of us even had a chance to try them out.

Not only have they fixed the Swift API for us, but they also open-sourced a new library which comes with 3 Clock types included: TestClock for unit tests, ImmediateClock for SwiftUI previews and UnimplementedClock for mocking!

SE-0376: Function Back Deployment

Links: Proposal Document 📝 | Review 🧵

This proposal suggests adding a new @backDeploy(before: ...) attribute to Swift which none of us app or framework developers will ever need. It's only relevant for those working on system libraries shipped with the OS like SwiftUI or Charts, but this new attribute might still have a big influence on app developers, too:

Once available, Apple could start introducing new APIs not only for the shiny new operating systems (e.g. iOS 17 & macOS 14) but they could also back-deploy some of the new APIs to older OS versions at the same time. App developers then wouldn't need to do anything specific to use back-deployed functions. Quite the opposite, they will be able to avoid availability checks and fallback code like this:

// without back-deployment
if #available(iOS 16.0, *) {
   callSomeShinyNewFunction()
} else {
   // fallback on older systems
}

// with back-deployment
callSomeShinyNewFunction()

When using a function marked with @backDeploy the compiler will intelligently check the target SDK of the app being built against and if it's a version that natively supports the new feature, it will use the system framework, mitigating app binary size increases and each app shipping with its own copy of the function.

Now, don't get too excited though. While this is really cool and could mean more new APIs will be available to use for teams who need to support OS versions 1-2 years back, there are still limitations. This proposal only discusses adding the attribute for functions, subscripts, and properties without storage. Types like enums and structs or protocol conformances aren't discussed yet, they are only mentioned as potential future directions.

Also, there are restrictions on which functions can be back-deployed, such as that they need to be statically dispatchable (e.g. final), which excludes all functions that are marked to be compatible with Objective-C via @objc. This means that it will be easier for Apple to back-deploy APIs in newer Swift-only frameworks like SwiftUI, Combine or Charts than it will be to do so with older Objective-C-based frameworks like UIKit & AppKit. Also, we don't know how many teams within Apple will make use of this new feature and how far back they will be able to back-deploy. Only time can tell. But it's exciting to see this topic is getting some love!

SE-0377: borrow and take parameter ownership modifiers

Links: Proposal Document 📝 | Review 🧵

This proposal gives Swift authors who are highly concerned about the performance of their code fine-grained control over some aspects of Automatic Reference Counting, the memory management feature of Swift. Two new parameter modifiers (like inout) are introduced for that, namely borrow and take.

The vast majority of app developers won't need to use these modifiers and should instead trust Swift's built-in memory management heuristics. For those who are interested, please read the full proposal to fully understand the new modifiers.

📧
To receive future issues via email, subscribe to the newsletter here.

Recently Active Pitches/Discussions

Some threads inside the “Evolution” category with activity within the last month I didn’t link yet. I’ll cover them in detail once (and if) they become proposals:


Want to see your ad here? Contact me at ads@fline.dev to get in touch.

Other Developments worth Mentioning

The Language Workgroup did some clean-up on 6 old proposals with unclear status, of which 3 were returned to discussion and 3 were rejected outright.

Slava Pestov announced a documentation book series digging into the details of how Swift generics work. If you're curious about this topic or if you (want to) work on the Swift compiler in general, you might want to read the free PDF posted here.

In the last issue I had already mentioned that parts of Swift are rewritten in Swift. But what I had totally missed is that also the parser for the SwiftSyntax library is currently being rewritten in Swift to get rid of the need for the C++ library lib_InternalSwiftSyntaxParser in tools like SwiftLint or BartyCrouch. This October update post summarizes the progress on this front and JP Simard also shared his experiences with the new parser in the same thread.

Speaking of C++ and updates, the C++ Interoperability Workgroup has shared their 8-months progress report.

Lastly, Sima Nerush, a student at Reed College, took some time to write about her experiences and learnings as part of the Swift Mentorship Program where she helped fix 4 bugs in Swift. If you're interested in becoming an active contributor to Swift yourself, set yourself a reminder for June next year when interest surveys are likely to reopen. The program is open to everyone, not just students!

And that’s it from my October update!

💁🏻‍♂️
Enjoyed this article? Check out my app RemafoX!
A native Mac app that integrates with Xcode to help translate your app.
Get it now to save time during development & make localization easy.
👨🏻‍💻
Want to Connect?
Follow me on 👾 Twitch, 🎬 YouTube, 🐦 Twitter, and 🦣 Mastodon.