What’s next for Foundation

Tons of great responses here, thank you everyone! I'll try to consolidate some replies here.

First, some high level clarifications on the API surface.

Darwin Foundation (what we will call 'Foundation framework' to distinguish it) will be a superset of the package, because it will include all of the implementations we cannot remove or refactor as part of this work (stuff written in Objective-C or which we decide to omit from the package for some reason). Clearly we can't just yank the rug out from all existing apps on iOS or macOS. Therefore, the main task here is to refactor the code that we choose to have a common implementation into Swift and make that the core instead of C or ObjC.

We've prototyped this approach and are pretty sure it will work out well. A reimplementation of Calendar in Swift is 1.5x to 18x as fast as the C one (calling from Swift in various synthetic benchmarks like creation, date calculation). And it's completely compatible with the existing C and ObjC entry points, too.

We can choose to omit existing methods from included types in the package, but we can't remove it from Darwin for compatibility reasons. We could implement those methods partially in ObjC (available only on Darwin) and partially in Swift (available everywhere), or just bring that API along to Swift so we have a more unified implementation. I think it will be a case-by-case decision, but we are likely to choose the latter for maintainability and usability reasons.

We can also choose to add new methods to these types, where we think it will add value (e.g. the suggested improvement of hex utilities to Data). That is the purpose of developing an open contribution process. New methods will be available on all platforms, unless we decide it's irrelevant on some for a good reason.

The process can also be used to deprecate existing API. I do want to note that Foundation has a high bar for deprecation. It can be very disruptive to client apps when they upgrade the SDK. We generally only deprecate when:

  • The API is actively harmful for some reason,
  • After giving plenty of notice and,
  • having replacements available for a significant amount of time.

This work is going to take some time, so we will start with the contents of Essentials and Internationalization and see how it goes as we progress through all of those API. Networking and XML will come later.

Now, about some of the concrete types:

Stream, Port, Timer

Stream, Port, and Timer are inherently tied to RunLoop, which is itself inherently thread-based. Given the move away from concrete threads with the introduction of tasks in structured concurrency, it doesn't seem like these API are the right model to encourage going forward. I'm still open to discussion on that point.

It may be the case that we could use a new API for structured concurrency that adjusts the fire date like Timer and RunLoop do. I'm not sure.

NSCoding

NSCoding is inherently tied to NSObject and keyed archiving to the Objective-C runtime for class names. I don't see a lot of value in attempting to reimplement it in Swift. The existing swift-corelibs-foundation repository will continue to exist (perhaps with a different module name?) in the future, if there is a compatibility requirement to use it on non-Darwin platforms.

Lock

This one is controversial for sure. In fact, Foundation needs it internally. However, it's unclear to me if we should bring it forward into the package as a public type or not. I'm open to discussion.

Date

We litigated this one extensively in the previous discussions about Duration and the conclusion there was to keep it in Foundation. We'll honor that decision by keeping it in Essentials. Date itself is just a Double, really, so it can be used independently of any dependency on ICU. Formatting it, or using it with Calendar or TimeZone does currently require ICU support and therefore those APIs will be in the Internationalization module.

Decimal

I think we may end up needing this for JSONSerialization, I'm not sure. If so it'll be in Essentials. Decimal suffers more than some other types from a poor translation into Swift's ideas around numerics, so it may deserve some additional attention.

Forward/backward compatibility and module names

We have some work ahead of us to figure out how we transition the platform to the new package. Since Foundation is shipped with the toolchain on Linux and the SDK on Darwin, calling the new package Foundation will result in some conflicts. We've decided not to rename it (because it's always going to be Foundation on Darwin), so I think we will need some kind of mode switch. I could imagine, for example, Swift 6 mode renaming the existing swift-corelibs-foundation module to get it out of the way. Another option is to provide a compiler flag for both Darwin and Linux like --no-sdk which prevents the import of anything from the toolchain on Linux or the SDK on Darwin, so the packages you included are the only option and the potential for a conflict is removed.

I think we may choose to have the package simply called FoundationPreview as a very first step, so we can give ourselves some space to resolve these questions.

39 Likes