At some point, I think we should remove PathName.
There is almost no reason to use it, ever.
Just about everything you need to do with paths is already supported in String. Going through PathName just introduces complication and it’s unnecessary in your example.
I’d just take it out.
I think the idea that there is no reason to use or want PathName is a bit extreme, and also cuts against the grain of what I see happening in other high-level, cross-platform programming languages. I would advocate for something a little different. Right now, the utilities for manipulating paths as filesystem objects are spread across String, PathName, and File. I think it would be a good move to consolidate them all under PathName, much like C++ and Python’s own filesystem libraries (std::filesystem formerly boost::filesystem, pathlib formerly os.path), deprecating and removing path-manipulation utilities elsewhere. There are good design reasons for doing this, in my opinion.
For one, many operations on paths make no sense in the context of string manipulation – component-wise path equality, component iteration, concatenation, and the operation of taking two absolute paths and making the first relative to the second. Attaching them to the String interface is confusing and also requires them to return defined results even when the operands are nonsensical as paths.
At the same time, many operations on strings make no sense in the context of path manipulation – split, rotate, scramble, string concatenation, padding, etc. Having them available on paths is an invitation for half-solutions where the correct, platform-agnostic version of path manipulation code is missed because abstracting over directory separators is difficult compared to hard-coding the one locally in use. Another possible source of mistakes is treating
++ as “just as good” as
+/+; even if one use of
++ works because of local guarantees, copy-pasting it somewhere else may cause issues.
Combining the String and Path/PathName interfaces on the same object leads to awkwardness, because we have to then also make a choice about where to put methods that actually manipulate filesystem objects, like
chmod. Putting them on
String more or less requires adding the word
path to the names to disambiguate and clarify their purpose and avoid naming collisions. It starts to feel like this isn’t really String’s job.
On the other hand, keeping them separate on File as they are now is also unsatisfying, because we also have some filesystem-touching functions on both String (
pathMatch) and PathName (
files). Plus, these methods on File are pretty unwieldy, just compare
p.exists for example. After all, if we have a PathName object, it typically represents some possible past, present, or future object on the filesystem that we likely want to interact with.
In my opinion, most of the current awkwardness with PathName comes from the fact that it does not offer a very full interface, and also has bad support throughout the rest of the class library. Neither of these are really problems with the general concept of a Path type which is separate from a String type, just the implementation.
In summary, I think moving all FS ops from File and String to PathName would be a better long term solution than migrating PathName to String regardless of whether File’s ops are kept in File or also moved to String. That is, if any such migration is being considered at all. This would be a complicated migration regardless of how it’s done. Another option would be to start fresh with a more accurately named Path class; if we were going to migrate lots of FS ops there it would be worth it to get the name right, I think.
Btw, I only listed C++ and Python above because I’m most familiar with those. I’d be happy to hear if there are path manipulation paradigms in other languages that people think are worth of praise or imitation.