The adoption of `import FoundationEssentials` throughout the package ecosystem

Hey everyone,

We had discussed this issue over the past few weeks in the Ecosystem Steering Group together with the Foundation Workgroup to come up with guidance here. It took us a bit longer since there is some complexity with this adoption. Below is our guidance to the ecosystem.


The Ecosystem Steering Group thinks the adoption of FoundationEssentials is an important ecosystem-wide problem to tackle to achieve our goal of a flourishing Swift package ecosystem across all use cases. As discussed in this thread, FoundationEssentials provides a subset of the Foundation APIs which result in significantly reduced binary size. This is important for many use cases such as WASM or Android. However, to take advantage of this reduced binary size, every single package in the graph needs to ensure it only imports FoundationEssentials.

The current primary problem with adopting FoundationEssentials broadly is Swift's leaky import behavior. Changing from an import Foundation to an import FoundationEssentials is potentially source breaking as shown by this example:

// Module A
import Foundation

// Module B
import ModuleA

let s = "foo"
print(s.lengthOfBytes(using: .utf8))

Today, this builds because the import Foundation in Module A leaks public extensions on stdlib types into clients of Module A (i.e. Module B). In this case, func lengthOfBytes(using:) is a Foundation extension on String. If Module A imports FoundationEssentials instead, Module B fails to build.

Strictly speaking, changing from Foundation to FoundationEssentials would require a new major version. Due to this, we discussed three different options:

  1. Wait for the natural next major version of packages to change their imports.
  2. Recommend packages to change the import and release a new major version.
  3. Change the import and release a new minor while accepting the small potential for a source break.

We ruled out option 1 and 2 since new major versions are even more disruptive for the ecosystem as we have seen with the grpc-swift 2 major release. Therefore, we landed on option 3 since we believe the upsides heavily outweigh the potential downsides here. Importantly, this recommendation only applies to packages that only depend on Foundation APIs that are available in FoundationEssentials. Packages that use APIs that are only available in full Foundation are not expected to make a change here. Concretely, our recommendation for packages is:

  1. Where applicable, change Foundation imports to this:
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
  1. Setup CI that tests your package across platforms since FoundationEssentials is not available everywhere and it is important to ensure that your package builds with either of the two imports.
  2. Release a new minor version of the package with release notes clearly indicating this expected potential source break.

In addition to the adoption of FoundationEssentials, we also discussed the broader problem of leaky imports with regards to the larger ecosystem. We believe that Swift's leaky import behavior is a bug and that most package authors are not even aware that changing an import can result in a source break. Hence, many popular packages in the ecosystem are not providing source stability guarantees for this. To combat this problem actively, we encourage package maintainers to adopt the two upcoming language features InternalImportsByDefault and MemberImportVisibility proactively. Similar to the adoption of FoundationEssentials, the adoption of these upcoming features can result in potential source breaks. However, since almost no package is guaranteeing this stability in the first place, we strongly believe it is better to adopt those features quickly throughout the ecosystem to remove the potential of any unintended source breaks.

We hope that this will allow the ecosystem to transition to FoundationEssentials relatively quickly to unlock the binary size savings and that the upcoming feature adoption will provide a healthier and stabler ecosystem.

23 Likes