Conversation
lib/path/default.nix
Outdated
There was a problem hiding this comment.
This is clever but cumbersome, and not more convenient than
if hasPrefix a b
then subpath.join (removePrefix a b)
else throw "oopsie"We can still keep the good error messages in case people don't bother to do the check on their own.
If you're worried about consistency with passing around components instead of a subpath string – well, there is the type signature and one can always add a doc comment stating this is more efficient and one can easily bake it back together into a string with subpath.join.
An alternative is providing a "convenience" layer such as removePrefixAsSubpath (giving the one doing more work a longer name), but this is more to type than the explicit join.
There was a problem hiding this comment.
The problem is that it's not clear what removePrefix should return. If it returns a subpath string but you need coomponents, you'd have to parse them (I want to add subpath.components for that in the future), but that operation is a bit expensive.
In turn if removePrefix were to return components, it would be inconsistent because append doesn't take components, but rather a subpath.
To make it obvious and unambiguous what the function returns and have both use cases, we could do removePrefixAsSubpath and removePrefixAsComponents, but at that point an API as suggested in this PR feels cleaner.
For more context, I would also like a function like this in the future:
lib.path.parts :: Path -> {
root :: FilesystemRoot;
components :: [ Component ];
subpath :: Subpath;
}
Which would have a very similar interface, and where alternatives wouldn't be as great.
Maybe that function should come before this one.
There was a problem hiding this comment.
lib.path.parts :: Path -> { root :: FilesystemRoot; components :: [ Component ]; subpath :: Subpath; }
This is what's currently called deconstructPath somewhere internally, right?
There could be two sets of APIs, one for component-wise paths and one for strings. We also originally discussed a structured representation that is string-coercible, but you deemed that too expensive performance-wise.
I'm personally inclined to keep the interface and implementation simple even at the potential cost of performance at scale. We have nice primitives that would make additions almost trivial, and I think we should use them. If that indeed becomes a real performance problem, one can still go measure and figure out alternatives. For now I'd prefer handling strings as we started out with. It's also more predictable for the user, as at each step you'd get out what you expect a path to look like. Otherwise we're opening up the can of design worms all over again.
There was a problem hiding this comment.
The problem is that it's not clear what
removePrefixshould return.
I think I'd expect a subpath because these functions have string counterparts.
I agree with @fricklerhandwerk that it's ok to have more functions.
potential cost of performance
I was going to say that __toString is cheaper than outPath, but I guess we're dealing with a list 🤡
Just an Attr of 24 bytes added to an existing contiguous array and no extra thunk if __toString doesn't have the value in its scope, but rather uses the argument. iirc.
There was a problem hiding this comment.
Fair enough, I now changed this function to return a subpath string. I also created #242695 to get the components of a subpath.
9a7dfac to
1a8329d
Compare
1a8329d to
6626d8c
Compare
Description of changes
Adds a new function to
lib.path:lib.path.removePrefix: Remove the first path as a component-wise prefix from the second path.Originally split off from #210423, but changed after reconsideration here. Part of the path library effort.
Depends on #237610now mergedThis work is sponsored by Antithesis ✨
Things done