(Reposting my Slack comment re relative paths.)
I had an idea, inspired by @ExpandingMan’s decision in FilePaths2.jl to exclude relative paths.
The idea I like is having two types: Path which is always an absolute path and PathSegment which is an offset that can be concatenated to an Path or to a PathSegment, just like Year can be concatenated to a Year or to a Date .
I have two basic reasons.
State. Current working directory is global mutable state; I want to avoid a situation where runtime behavior depends on it. So if p"foo" expands to Path("/home/user/src/proj/foo") at compile time, then cd won’t affect the target as it’s already resolved to an absolute path.
Semantics. Path segments are common in real programs, and are semantically different from absolute paths. Path("/etc/hosts") has a lot of properties that PathSegment("foo") doesn’t have. Calling any filesystem methods on a path segment never makes sense and can only give wrong answers, which is a good indicator there are two different types living here.
Likewise there is often uncertainty over whether "foo/bar" is supposed to be relative to the current working directory or will be concatenated with a base path. For example joinstring("/foo", "/bar") == "/foo/bar" but joinpath("/foo", "/bar") == "/bar" which can be confusing but could be made to fail at compile time, as two absolute paths cannot be concatenated and relative path segments won’t override absolute base paths.
Separating the types simplifies a library author’s job since they know exactly what kind of object they receive from a caller, and likewise communicates to users what kind of object is expected from them.