a common problem i face is i will have some module or library that Must Not depend on swift-system, or any other non-portable dependency. it will wrap something that is semantically a FilePath.Component.
struct SomeResource
{
var directoryName:FilePath.Component = "Photos"
}
but of course, we cannot utter the type FilePath.Component in SomeResourceModule, so the best we can do is
struct SomeResource
{
var directoryName:String = "Photos"
}
but this just adds complexity to the code that imports SomeResourceModule, along with System, because you need to handle all the cases where directoryName is not actually a valid FilePath.Component.
guard
let directory:FilePath.Component = .init(resource.directoryName)
else
{
throw ErrorThatShouldBeStaticallyUnreachableInstead.init()
}
this feels like a common problem in Swift, where you can’t actually use the currency types without pulling in the rest of the dependency.
IMO this is something that the Version package has achieved really well for semantic versions. Perhaps we need some official swiftlang micro libraries for the various other currency types which haven’t made it or will never make it into foundation?
Ideally we’d also then migrate swift-system et al to use those micro libraries and provide extensions for the purpose-specific stuff they require such as os string representations or whatever swift-system provides in its filepath type.
You want to use FilePath, but it is not portable (or at least, not portable enough for your requirements), so you used something else that is more portable. Obviously FilePath cannot be available on a system with unknown file path format. That seems fine to me, and I don't see how this would be different if it were a micro-package.
You can write import struct System.FilePath to restrict what your file uses from System, if that's your concern.
Providing more detail limits which symbols are imported — you can specify a specific submodule or a specific declaration within a module or submodule. When this detailed form is used, only the imported symbol (and not the module that declares it) is made available in the current scope.
FilePath is “just” a wrapper around a string (although the actual implementation is a little more complicated because FilePath currently prefers UTF-16 in some places, though i feel that it should not.)
FilePath has operations that depend on the operating system, but the type itself ought to be usable as a stored property without OS-dependent code.
import struct does nothing to mitigate the actual dependency on the entirety of SystemPackage.
No it isn't. The code-units of a FilePath have both a system-dependent size and system-dependent meaning. On some platforms they are 8-bits wide, and on others they may be larger, and on some platforms they are known to be Unicode, whereas on others they are just opaque.
A core principle of FilePath -- and indeed everything in swift-system, is that they are system-dependent. Even if by coincidence some properties happen to align on some platforms, you shouldn't treat that as meaningful and we definitely should not use that as a basis to restrict the ability of the type or the library to support even more divergent systems in the future.
I mean, what would we even gain from it? A type with no operations? It couldn't even be initialised (not in the general case).
I think you are trying to make a square peg fit a round hole, as it were - FilePath does not seem to meet your requirements.
I haven’t looked at it myself so I don’t know for sure what you mean, but I believe Windows paths are allowed to contain unpaired UTF16 surrogates, and Swift’s UTF8 validation doesn’t like that.
@frozen public
struct SomeResource
{
var directoryName:FilePath.Component
public
init(directoryName:FilePath.Component) { ... }
}
it’s the client module’s task to construct and supply the actual directoryName, but code that uses SomeResource can safely assume that it wraps some valid instance of FilePath.Component.
right now, to achieve this kind of guarantee, SomeResourceModule has to link SystemPackage, which means anything that cohabits with SomeResource also links SystemPackage into its clients, even if it never interacts with FilePath. this is a common attribute of Swift modules and causes a lot of things to weigh a lot more than they need to.
Apologies, I was coming at this from the widely used currency type side of things not the code size side of things. The Foundation import wouldn’t be too hard to fix with a trait. Many currency types (such as paths) benefit from having some default Foundation interoperability to make them easy to work with out of the box imo, so an opt-out Foundation trait seems reasonable for situations where foundation is undesirable (a relatively small/advanced subset of use-cases in today’s Swift ecosystem).