There's a lot of concepts, concerns, and topics to grapple with here. I think it might make sense to divide up some of this discussion into threads that can progress somewhat independently. Here's my attempt at teasing them apart.
Governance and swiftlang org on Github
There seems to be broad support for migrating the repo over to swiftlang. This will need some guidance by a steering group and is a prerequisite that can be tackled independently.
For ongoing governance, I think the Foundation Workgroup is the right fit. Any objections or other suggestions?
Motivation clarification: Types in toolchain API
When types are versioned together in the toolchain, they can appear in each other's API.
For example, Data has the following:
extension Data {
init(contentsOfFile path: String)
func write(toFile path: String, ...)
init(contentsOf url: URL, ...)
func write(to url: URL, ...)
}
It's not unreasonable to also want a FilePath overload in a context where FilePath is visible:
extension Data {
init(contentsOf path: FilePath) throws
func write(to path: FilePath, ...) throws
}
and a FileDescriptor overload in a context where FileDescriptor is available:
extension Data {
init(reading fd: FileDescriptor) throws
func write(to fd: FileDescriptor, ...) throws
}
A very important and related, but potentially separate, topic is the specifics of module organization and visibility. I.e., what imports are necessary for what types to be visible where.
FilePath migrates to toolchain
There is broad support for FilePath migrating from being vended by a package to being vended by the toolchain. This would mean that FilePath is versioned with everything else in the toolchain, and thus can appear in API. There's then the question of what the import statement should be. Note that when a type is in the toolchain, it can move between modules, meaning the specific import statement can be refined over time.
FilePath is your target operating system's concept of a path, including the encoding (e.g. UCS2/WTF-16 vs bag-of-bytes). The name System.FilePath is not an unreasonable name for this type. It's "cross platform" in the sense that there might be a common API between some platforms, that is it might be more or less "portable" in the POSIX sense. It's not a "cross platform" abstract notion of location because it actually encodes a path as understood by your specific OS. It could also be Swift.FilePath, that is it is brought in from the implicit import that every Swift program has. Or it could be some other module, but we'd have to pick a module for it to land in.
FilePath is different than some other systems-level types in that it as a concept reaches higher up the tech stack than say, FileDescriptor.
Do we have general agreement that it is a non-goal to migrate only the type but none of the syntactic operations on it? That is, we're talking about migrating the both type and the useful operations on it together.
FileDescriptor and other low-level types and concerns
This thread didn't talk much about FileDescriptor specifically, but it is an example of a low-level currency type that makes sense to unify across the ecosystem. It is portable in the POSIX sense and there's real correctness value to unifying on it (e.g. closeAfter has to handle tricky edge cases).
While we can migrate FilePath as a one-off special case (because it is so cross-cutting), that doesn't help other libraries that care about file descriptors, such as Foundation and Swift Subprocess (which uses both FilePath and FileDescriptor in API).
Tooling improvements and release strategy
The release cadence and versioning concerns are real pain points. I think there are tooling improvements and release process changes that can greatly address them. (I'm sketching possibilities here, not claiming technical feasibility).
When a type moves from a package to the toolchain, we could provide type-converting initializers and migration methods. If we had the means to automatically apply these for specific circumstances, that would greatly ease migration and allow for a more gradual move of types over time.
On the release management side, we could release delta packages containing changes since a given toolchain version, allowing the package to ship new functionality without waiting for the next toolchain release.
This should probably be discussed more broadly, as it's a matter that affects more than just System.
Methods or function bodies outside the toolchain
I want to see whether we have general agreement that it is an explicit non-goal for a developer to have to write multiple imports for basic functionality on a type. That is, we're not advocating for a situation where developers have to workaround our not being able to solve the versioning and release problem. Developers shouldn't have to write:
import SystemTypes // Give me FileDescriptor as a currency type
import SystemFunctions // Now give me methods on FileDescriptor
The question is more about whether and how to keep certain functionality on the vended-by-package side of the fence. io_uring is a very clear candidate for this kind of treatment, but any new syscalls added could be handled similarly. It gets complicated when those involve new types and this clearly could benefit from better tooling.
Developer facing doc/discovery
Another important concern is how to address the problem of documentation and discoverability of what is platform-specific and what is not. This is a broader problem and there's a need for solutions other than leaning on module names to organize this. Modules carry many concerns beyond communicating platform availability, and I don't think they're the right tool for this particular problem.
"Cross-platform" can also quickly get nuanced when System is involved, as it's more about groups of platforms over which API may be supported or "portable" (in the POSIX sense). That is, an API might be cross platform if your platforms are Darwin, Linux, and FreeBSD (and others) but not for Windows. Note that even FilePath being available requires that your target has a file system in the first place, which might not be the case.
This seems like a larger and broader, and potentially separate, discussion.