sorry for the rant, but i was recently writing some python scripts, and had to fill in the swift-side parts, and i’m becoming aware of just how much less productive i am using SystemPackage’s APIs, compared to os.path.
put simply, FilePath is just too safe. the amount of boilerplate needed for the simplest operations just feels excessive. it’s like String indexing, but taken to an extreme.
to walk through an example of a simple task that’s way over-complicated by FilePath, i had a text file with a list of directories, one on each line:
directories.txt
foo
bar
baz
i read the file contents, and split on newlines, to get an array of [Substring]:
func loadDirectoryList(from path:FilePath) throws -> [Substring]
{
try self.read(from: path).split(whereSeparator: \.isWhitespace)
}
next, i try to iterate over the list of directories, constructing a relative path with each directory as the last path component:
for directory:Substring in loadDirectoryList(
from: .init(root: nil, components: "workspace", "directories.txt"))
{
let directory:FilePath =
.init(root: nil, components: "workspace", .init(String.init(directory)))
}
first, why do i have to write root: nil to get a relative path? why can’t there just be a static constructor like .relative("workspace", "directories.txt")?
second, why do i have to copy directory:Substring to a String in order to construct a FilePath.Component? why can’t it just take some StringProtocol like everything else?
finally, it doesn’t even compile, because FilePath.Component.init(_:) is failable:
error: value of optional type 'FilePath.Component?' must be unwrapped
to a value of type 'FilePath.Component'
at the same time, FilePath.Component is ExpressibleByStringLiteral, which strikes me as inconsistent. if i want to refactor say the "workspace" directory into something configurable, i can’t just drop in a .init(workspaceName), since that would become optional.
pretty much all of this feels completely pointless to me. the text file will never contain empty lines or '/'characters, and nobody besides SystemPackage accepts FilePath anyway, they would all inevitably be converted back into String. for example, all of SwiftNIO’s file-based APIs take String, not FilePath.