Proposal: System.FilePath: current directory should be ".", not ""

See http://hackage.haskell.org/trac/ghc/ticket/2034 to which I have attached a fairly simple patch. All the tests pass. The main change is that splitFileName "foo" = (".", "foo") and takeDirectory "foo" = "." and "." > x = x Discussion period: 2 weeks (5 October) Cheers, Simon

On Mon, 2009-09-21 at 12:00 +0100, Simon Marlow wrote:
The main change is that
splitFileName "foo" = (".", "foo")
and
takeDirectory "foo" = "."
and
"." > x = x
So to re-iterate the point made in the ticket, the principle here is that the representation of the current directory is "." and not "". This lets us safely use results of System.FilePath functions as arguments to system and directory functions without having to check for "". However the principle is not without exception, we also want to elide the explicit representation of the current directory when it is not needed. If these are the principles then can we look at whether we apply them elsewhere in System.FilePath consistently? What about: joinPath [".", "foo"] should it be "./foo" or "foo" ? If "./foo" then it's not the same as >, if the latter then we loose the property Valid x => joinPath (splitPath x) == x it would be some kind of limited normalisation. So I'm happy with the first two changes, I'm less convinced about changing > to elide "." on the left. Perhaps people who worry about leading "./" when the FilePath is displayed to the user should just use normalise. That's what they do now and we seem to get along ok. Some people have mentioned before that some systems (though not the native low level POSIX interfaces) do actually distinguish "./blah/blah" from "blah/blah". The distinction is whether a file is relative to the current directory or to some other unspecified root (eg a search path). Unix shells make this distinction for example when running "a.out" vs "./a.out". The latter is independent of the current $PATH, it really refers to the one in the current directory, not any such file on the $PATH. On a related note, when I have experimented with designing a typed version of FilePath, one of the things I wanted to distinguish in the types is exactly this thing about "relative to something specific" (eg relative to "/" or ".") vs "relative to something not yet specified". Another terminology might be "complete" and "incomplete". The OS file manipulation functions would only work on complete filepaths. Duncan

On 22/09/2009 16:43, Duncan Coutts wrote:
On Mon, 2009-09-21 at 12:00 +0100, Simon Marlow wrote:
The main change is that
splitFileName "foo" = (".", "foo")
and
takeDirectory "foo" = "."
and
"."> x = x
So to re-iterate the point made in the ticket, the principle here is that the representation of the current directory is "." and not "". This lets us safely use results of System.FilePath functions as arguments to system and directory functions without having to check for "".
However the principle is not without exception, we also want to elide the explicit representation of the current directory when it is not needed.
If these are the principles then can we look at whether we apply them elsewhere in System.FilePath consistently?
What about:
joinPath [".", "foo"]
should it be "./foo" or "foo" ?
If "./foo" then it's not the same as>, if the latter then we loose the property
Valid x => joinPath (splitPath x) == x
it would be some kind of limited normalisation.
So I'm happy with the first two changes, I'm less convinced about changing> to elide "." on the left. Perhaps people who worry about leading "./" when the FilePath is displayed to the user should just use normalise. That's what they do now and we seem to get along ok.
So this subject was discussed between Ian and myself in the original thread, see e.g. http://www.haskell.org/pipermail/libraries/2007-December/008776.html The conclusion was that in the filesystem semantics "./foo" is equal to "foo", but the string passed to rawSystem (and execp()) is not a FilePath, it is something like Either FilePath String. However, there are some oddities with the current proposal. e.g. splitFileName "./foo" == ("./", "foo") "./" > "foo" == "./foo" The current proposal just about hangs together because the tiny bit of normalisation that > does exactly undoes the creation of "." in splitFileName, and there's no other way that splitFileName can generate ".". That's a terribly fragile property. If we "fixed" > to do more normalisation, then we would no longer have the property that uncurry (>) (splitFileName x) == x (*1) I don't actually care about the details here as long as we have a story that is reasonably consistent. My main concern is that isValid x => isValid (takeDirectory x) the lack of which is the main problem with the current formulation, as you (Duncan) mentioned above. Perhaps we should drop the magic normalisation that > does, and apply the normalise function to both sides of (*1). There would probably be a bunch more properties that would have to change too, I'm guessing that normalise would proliferate. Incedentally, I dislike the way that trailing slashes are treated in the current filepath implementation. A trailing slash is significant in POSIX: $ ls -l foo lrwxrwxrwx 1 simonmar GHC 15 2009-09-23 14:04 foo -> /does/not/exist $ ls foo foo@ $ ls foo/ ls: cannot access foo/: No such file or directory The path with the trailing slash dereferences a symbolic link, and may fail if the link points nowhere. I think trailing slashes should be dropped by splitFileName. Cheers, Simon

Hello Simon, Wednesday, September 23, 2009, 5:17:58 PM, you wrote:
The main change is that
let me ask another question - are it's expected to raise FilePath library major version number? i ask as developer who is used copy of FilePath deep inside of my program. if i rely on hackage for providing the library, it was very unpleasant to see that program has become buggy w/o any notice with new version of FilePath incompatible with previous one from this POV, it was much better to provide one more function for doing new thing. you, GHC developers, use a lot of libraries built-in in GHC source tree. just imagine what you start using hackage and discovered that you need to fix a lot of bugs appeared in your program after every major GHC release -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

On 23/09/2009 14:36, Bulat Ziganshin wrote:
Hello Simon,
Wednesday, September 23, 2009, 5:17:58 PM, you wrote:
The main change is that
let me ask another question - are it's expected to raise FilePath library major version number?
Yes, this is an incompatible change and would therefore warrant a version number bump. OTOH, I validated GHC with this change and it worked without modification. Cheers, Simon

On Wed, 2009-09-23 at 14:17 +0100, Simon Marlow wrote:
So I'm happy with the first two changes, I'm less convinced about changing> to elide "." on the left. Perhaps people who worry about leading "./" when the FilePath is displayed to the user should just use normalise. That's what they do now and we seem to get along ok.
So this subject was discussed between Ian and myself in the original thread, see e.g.
http://www.haskell.org/pipermail/libraries/2007-December/008776.html
The conclusion was that in the filesystem semantics "./foo" is equal to "foo", but the string passed to rawSystem (and execp()) is not a FilePath, it is something like Either FilePath String.
Right. The file system OS calls take complete file paths, relative to "/" or implicitly relative to ".". system/rawSystem (and some other libs) take either a complete filepath, or an incomplete one which they then complete relative to some search path. In my experimental typed filepath it'd be Either CompletePath IncompletePath. So I would consider both as file paths (though different types). System.FilePath is pretty good for manipulating incomplete (relative) paths so I think it'd be a shame to declare that what rawSystem takes is not a FilePath and thus we do not need to consider functions of its ilk.
However, there are some oddities with the current proposal. e.g.
splitFileName "./foo" == ("./", "foo") "./" > "foo" == "./foo"
The current proposal just about hangs together because the tiny bit of normalisation that > does exactly undoes the creation of "." in splitFileName, and there's no other way that splitFileName can generate ".". That's a terribly fragile property.
So if we take the first bit of your proposal and not the second we have: splitFileName "foo" == ("./", "foo") "./" > "foo" == "./foo" and thus we do not have: uncurry (>) (splitFileName x) == x because we end up with "foo" an "./foo" However I think that's fine. The splitFileName function is asking for the directory part of a relative/incomplete filepath and expecting it to be a real directory. Thus we are interpreting the original filepath as a complete filepath that is relative to ".". So given that by applying splitFileName we are taking that interpretation it's ok to get back "./foo", because we in that context we really were interpreting "foo" as "./foo".
If we "fixed" > to do more normalisation, then we would no longer have the property that
uncurry (>) (splitFileName x) == x (*1)
I don't actually care about the details here as long as we have a story that is reasonably consistent. My main concern is that
isValid x => isValid (takeDirectory x)
the lack of which is the main problem with the current formulation, as you (Duncan) mentioned above.
Right.
Perhaps we should drop the magic normalisation that > does, and apply the normalise function to both sides of (*1). There would probably be a bunch more properties that would have to change too, I'm guessing that normalise would proliferate.
We don't want full normalise, it does too much. So the interpretation I quite like is the complete/incomplete one. Under that model splitFileName can be used for both complete and incomplete paths. splitFileName :: AnyFilePath path => path -> (path, IncompletePath) For complete paths we get back a complete directory part and an incomplete relative path for the filename. For incomplete paths we get back another incomplete directory part. What you want though in the existing untyped interface is that takeDirectory gives you a complete path (so you can pass it to system function), which means the input must also have been a complete path. I think this interpretation justifies: uncurry (>) (splitFileName "foo") == "./foo" In a typed version we could have both interpretations depending on the type and the property would hold in both I think. Does that help or just add more mud? :-)
Incedentally, I dislike the way that trailing slashes are treated in the current filepath implementation. A trailing slash is significant in POSIX:
$ ls -l foo lrwxrwxrwx 1 simonmar GHC 15 2009-09-23 14:04 foo -> /does/not/exist $ ls foo foo@ $ ls foo/ ls: cannot access foo/: No such file or directory
The path with the trailing slash dereferences a symbolic link, and may fail if the link points nowhere.
I think trailing slashes should be dropped by splitFileName.
I don't follow. Isn't it exactly because they are significant that they should be preserved. There are System.FilePath functions for testing for, adding and removing trailing slashes. Duncan

On 24/09/2009 18:20, Duncan Coutts wrote:
However, there are some oddities with the current proposal. e.g.
splitFileName "./foo" == ("./", "foo") "./"> "foo" == "./foo"
The current proposal just about hangs together because the tiny bit of normalisation that> does exactly undoes the creation of "." in splitFileName, and there's no other way that splitFileName can generate ".". That's a terribly fragile property.
So if we take the first bit of your proposal and not the second we have:
splitFileName "foo" == ("./", "foo") "./"> "foo" == "./foo"
and thus we do not have:
uncurry (>) (splitFileName x) == x
because we end up with "foo" an "./foo"
However I think that's fine. The splitFileName function is asking for the directory part of a relative/incomplete filepath and expecting it to be a real directory. Thus we are interpreting the original filepath as a complete filepath that is relative to ".". So given that by applying splitFileName we are taking that interpretation it's ok to get back "./foo", because we in that context we really were interpreting "foo" as "./foo".
I've amended the patch as suggested above, it turned out to be not too hard. A few places were using splitFileName internally, and that broke some properties, e.g. -- > Valid x => replaceFileName x (takeFileName x) == x replaceFileName :: FilePath -> String -> FilePath replaceFileName x y = dropFileName x > y the property doesn't hold any more because dropFileName "foo" == "./". So I worked around cases like this with an internal version of splitFileName with the old semantics. This isn't a big problem - it just means we get to keep some of these nice simple equality properties, which are arguably wrong anyway, and fewer "./" prefixes will show up to surprise users. Neil's comprehensive test suite still passes with the new patch. Ticket, with new patch attached: http://hackage.haskell.org/trac/ghc/ticket/2034 The discussion deadline has long passed, so I propose we have another 2 weeks (18 November). Cheers, Simon

On Wed, 2009-11-04 at 10:00 +0000, Simon Marlow wrote:
I've amended the patch as suggested above, it turned out to be not too hard.
[..]
Neil's comprehensive test suite still passes with the new patch.
Ticket, with new patch attached:
http://hackage.haskell.org/trac/ghc/ticket/2034
The discussion deadline has long passed, so I propose we have another 2 weeks (18 November).
I support this new proposal. To summarise for people who have not been paying full attention: Currently: takeDirectory "Main.hs" = "" Proposed: takeDirectory "Main.hs" = "./" The purpose being that one can always take the directory and get a valid path to use with a file system function, eg createDirectory. Unchanged behaviour: "./" > "Main.hs" = "./Main.hs" It was initially proposed that > eat "./" on the left hand side but the current proposal leaves the behaviour of > unchanged. Duncan

Excerpts from Duncan Coutts's message of Wed Nov 04 12:11:49 +0100 2009:
On Wed, 2009-11-04 at 10:00 +0000, Simon Marlow wrote:
I've amended the patch as suggested above, it turned out to be not too hard.
[..]
Neil's comprehensive test suite still passes with the new patch.
Ticket, with new patch attached:
http://hackage.haskell.org/trac/ghc/ticket/2034
The discussion deadline has long passed, so I propose we have another 2 weeks (18 November).
I support this new proposal.
So do I. -- Nicolas Pouillard http://nicolaspouillard.fr

http://hackage.haskell.org/trac/ghc/ticket/2034
The discussion deadline has long passed, so I propose we have another 2 weeks (18 November).
I support this new proposal.
So do I.
+1. Regards, Malcolm

I agree with the idea behind this proposal, but am pretty sure it will
break quite a few filepath things that I maintain. So +1, but also +1
for a really strong release announcement and version bump.
The problem with filepaths is that they lack much structure, and are
very system dependent - meaning every change will break something. A
lovely abstract type would be wonderful, but no one has yet released
such a library on hackage...
Thanks, Neil
2009/11/4 Duncan Coutts
On Wed, 2009-11-04 at 10:00 +0000, Simon Marlow wrote:
I've amended the patch as suggested above, it turned out to be not too hard.
[..]
Neil's comprehensive test suite still passes with the new patch.
Ticket, with new patch attached:
http://hackage.haskell.org/trac/ghc/ticket/2034
The discussion deadline has long passed, so I propose we have another 2 weeks (18 November).
I support this new proposal.
To summarise for people who have not been paying full attention:
Currently: takeDirectory "Main.hs" = ""
Proposed: takeDirectory "Main.hs" = "./"
The purpose being that one can always take the directory and get a valid path to use with a file system function, eg createDirectory.
Unchanged behaviour:
"./" > "Main.hs" = "./Main.hs"
It was initially proposed that > eat "./" on the left hand side but the current proposal leaves the behaviour of > unchanged.
Duncan
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

+1
On Thu, Nov 5, 2009 at 3:36 PM, Neil Mitchell
I agree with the idea behind this proposal, but am pretty sure it will break quite a few filepath things that I maintain. So +1, but also +1 for a really strong release announcement and version bump.
The problem with filepaths is that they lack much structure, and are very system dependent - meaning every change will break something. A lovely abstract type would be wonderful, but no one has yet released such a library on hackage...
Thanks, Neil
2009/11/4 Duncan Coutts
: On Wed, 2009-11-04 at 10:00 +0000, Simon Marlow wrote:
I've amended the patch as suggested above, it turned out to be not too hard.
[..]
Neil's comprehensive test suite still passes with the new patch.
Ticket, with new patch attached:
http://hackage.haskell.org/trac/ghc/ticket/2034
The discussion deadline has long passed, so I propose we have another 2 weeks (18 November).
I support this new proposal.
To summarise for people who have not been paying full attention:
Currently: takeDirectory "Main.hs" = ""
Proposed: takeDirectory "Main.hs" = "./"
The purpose being that one can always take the directory and get a valid path to use with a file system function, eg createDirectory.
Unchanged behaviour:
"./" > "Main.hs" = "./Main.hs"
It was initially proposed that > eat "./" on the left hand side but the current proposal leaves the behaviour of > unchanged.
Duncan
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

A lovely abstract type would be wonderful, but no one has yet released such a library on hackage...
I'm certainly not going to claim it's 'lovely' ... but there is now on hackage a library which offers an abstract type: http://hackage.haskell.org/package/pathtype It's very early days, hasn't been used in anger, doesn't support a lot of Windows things yet, but the basics do work. I'd be grateful for any comments (and of course patches!) Oh, and.... *System.Path> takeDirectory ("Main.hs"::RelFile) . --Ben On 5 Nov 2009, at 20:36, Neil Mitchell wrote:
I agree with the idea behind this proposal, but am pretty sure it will break quite a few filepath things that I maintain. So +1, but also +1 for a really strong release announcement and version bump.
The problem with filepaths is that they lack much structure, and are very system dependent - meaning every change will break something. A lovely abstract type would be wonderful, but no one has yet released such a library on hackage...
Thanks, Neil
2009/11/4 Duncan Coutts
: On Wed, 2009-11-04 at 10:00 +0000, Simon Marlow wrote:
I've amended the patch as suggested above, it turned out to be not too hard.
[..]
Neil's comprehensive test suite still passes with the new patch.
Ticket, with new patch attached:
http://hackage.haskell.org/trac/ghc/ticket/2034
The discussion deadline has long passed, so I propose we have another 2 weeks (18 November).
I support this new proposal.
To summarise for people who have not been paying full attention:
Currently: takeDirectory "Main.hs" = ""
Proposed: takeDirectory "Main.hs" = "./"
The purpose being that one can always take the directory and get a valid path to use with a file system function, eg createDirectory.
Unchanged behaviour:
"./" > "Main.hs" = "./Main.hs"
It was initially proposed that > eat "./" on the left hand side but the current proposal leaves the behaviour of > unchanged.
Duncan
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Sat, 2009-11-14 at 12:42 +0000, Ben Moseley wrote:
A lovely abstract type would be wonderful, but no one has yet released such a library on hackage...
I'm certainly not going to claim it's 'lovely' ... but there is now on hackage a library which offers an abstract type:
http://hackage.haskell.org/package/pathtype
It's very early days, hasn't been used in anger, doesn't support a lot of Windows things yet, but the basics do work.
Great.
I'd be grateful for any comments (and of course patches!)
So the type distinctions you are making are: * whether a path refers to a file or to a directory * whether a path is relative or absolute By relative and absolute it looks like you mean whether it starts with the root "/" vs not. So "foo/bar.txt" and "./foo/bar.txt" are both considered as relative. Yes?
Oh, and....
*System.Path> takeDirectory ("Main.hs"::RelFile) .
:-) So in the similar design I was working on, instead of distinguishing relative and absolute, I distinguish incomplete and complete. I initially started with the relative/absolute distinction and moved onto this one. It'd be interesting to see which is most useful in practise. What I mean by complete is a path referring to an actual file/dir that you could pass to a system call. This means they are anchored to some point the system knows about, such a "." the current directory or "/" or "C:\". Then an incomplete path is one that is not anchored. Incomplete paths become complete by > them to a existing complete one (including the current dir). So the difference between this complete/incomplete notion and relative/absolute is for paths that are relative to the current directory. You would say "Main.hs" :: RelFile and readFile :: AbsRelClass ar => FilePath ar -> IO String and so readFile "Main.hs" is ok, and reads the file "./Main.hs" in the current directory. I would probably say, "Main.hs" :: IncompleteFilePath (though I think I used somewhat shorter type names than that!) and readFile :: CompleteFilePath -> IO String and thus readFile "Main.hs" is not well typed, instead it would be: readFile (currentDir > "Main.hs") because that gives us a complete path, and if we want that to be rooted at the processes' current directory, then we do so explicitly. My intuition with file paths in Cabal, is that this distinction would catch more bugs. Ideally cabal's building code would be independent of the current directory, but the fact that relative paths get automagically completed to being relative to the current directory means that it's very easy to break this property. The type distinction would enforce it, and you could see explicitly where paths are deliberately completed relative to the current directory (or some other root). On the other hand it doesn't quite align with people's notion of relative paths so people might hate it :-). There are various other distinctions one could try to make, the question becomes which type distinctions are useful and when does it just become too much. For example one could distinguish file names (with no directory part), or pure roots with no directory part (eg ".", "/", "C: \", "//server/share/"). Duncan

On 14 Nov 2009, at 14:02, Duncan Coutts wrote:
So the type distinctions you are making are:
* whether a path refers to a file or to a directory * whether a path is relative or absolute
Yep, that's the idea.
By relative and absolute it looks like you mean whether it starts with the root "/" vs not. So "foo/bar.txt" and "./foo/bar.txt" are both considered as relative.
Yes.
So in the similar design I was working on, instead of distinguishing relative and absolute, I distinguish incomplete and complete. I initially started with the relative/absolute distinction and moved onto this one. It'd be interesting to see which is most useful in practise.
What I mean by complete is a path referring to an actual file/dir that you could pass to a system call. This means they are anchored to some point the system knows about, such a "." the current directory or "/" or "C:\".
Then an incomplete path is one that is not anchored. Incomplete paths become complete by > them to a existing complete one (including the current dir).
So the difference between this complete/incomplete notion and relative/absolute is for paths that are relative to the current directory.
You would say "Main.hs" :: RelFile
and
readFile :: AbsRelClass ar => FilePath ar -> IO String
and so readFile "Main.hs" is ok, and reads the file "./Main.hs" in the current directory.
I would probably say, "Main.hs" :: IncompleteFilePath
(though I think I used somewhat shorter type names than that!)
and
readFile :: CompleteFilePath -> IO String
and thus readFile "Main.hs" is not well typed, instead it would be:
readFile (currentDir > "Main.hs")
because that gives us a complete path, and if we want that to be rooted at the processes' current directory, then we do so explicitly.
Ah, ok, I see. I can see the attraction to that.
My intuition with file paths in Cabal, is that this distinction would catch more bugs. Ideally cabal's building code would be independent of the current directory, but the fact that relative paths get automagically completed to being relative to the current directory means that it's very easy to break this property.
Interesting. One possible approach with pathtype as it stands would be a wrapper module which hides "readFile :: AbsRelClass ar => FilePath ar -> IO String" and exposes it only at the restricted type: "readAbsFile :: AbsFile -> IO String; readAbsFile = readFile". This blocks accidental reading of relative files and clients are forced to use something like 'makeAbsoluteFromCwd'. I don't think this is exactly the same as what you're suggesting (it doesn't permit the "completion" process to be separated from the reading), but I think it would be a way to catch some of the same bugs?
There are various other distinctions one could try to make, the question becomes which type distinctions are useful and when does it just become too much.
I think this is a very important point. It's definitely a balancing act. I have ondered whether even capturing Abs/Rel was overkill, but my current feeling (not yet based on much real-world experience) is that it is worth it. Cheers, --Ben

On Nov 14, 2009, at 09:02 , Duncan Coutts wrote:
On the other hand it doesn't quite align with people's notion of relative paths so people might hate it :-).
Seems to me this approach handles Windows better. There is no single "current directory"; it's one per drive letter (plus one for "default", which might not be a drive letter if you "cd" to a UNC path). It also handles building paths for processes launched somewhere not the current directory, which seems like a big win to me. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

On Wed, Nov 4, 2009 at 8:00 AM, Simon Marlow
the property doesn't hold any more because dropFileName "foo" == "./". So I worked around cases like this with an internal version of splitFileName with the old semantics. This isn't a big problem - it just means we get to keep some of these nice simple equality properties, which are arguably wrong anyway, and fewer "./" prefixes will show up to surprise users.
If FilePath was a newtype, could its Eq instance not distinguish between "foo" and "./foo"? Note that we must distinguish "./foo/../" of "./" because this may not be valid ("foo" does not exist) or may be something different ("foo" is a symlink). This Eq instance would just eat all superfluous "./". Cheers, -- Felipe.

On 04/11/2009 11:56, Felipe Lessa wrote:
On Wed, Nov 4, 2009 at 8:00 AM, Simon Marlow
wrote: the property doesn't hold any more because dropFileName "foo" == "./". So I worked around cases like this with an internal version of splitFileName with the old semantics. This isn't a big problem - it just means we get to keep some of these nice simple equality properties, which are arguably wrong anyway, and fewer "./" prefixes will show up to surprise users.
If FilePath was a newtype, could its Eq instance not distinguish between "foo" and "./foo"? Note that we must distinguish "./foo/../" of "./" because this may not be valid ("foo" does not exist) or may be something different ("foo" is a symlink). This Eq instance would just eat all superfluous "./".
Yes, but FilePath is not a newtype, and it would break a lot of code to make it one. That is not part of this proposal. Just in case this isn't clear: like most people, I (still) believe FilePath should be an abstract type, but that's a matter for separate discussion. Right now I'm concerned about fixing a small problem with the current API. Cheers, Simon

Duncan Coutts wrote:
Some people have mentioned before that some systems (though not the native low level POSIX interfaces) do actually distinguish "./blah/blah" from "blah/blah". The distinction is whether a file is relative to the current directory or to some other unspecified root (eg a search path). Unix shells make this distinction for example when running "a.out" vs "./a.out". The latter is independent of the current $PATH, it really refers to the one in the current directory, not any such file on the $PATH.
Just for reference, this comes up with shell settings other than just $PATH as well. For instance, cd in Bash looks through $CDPATH in the same way command selection looks through $PATH (i.e. the default value is "." which is sensible, but some folks like ".:~" to make their home dir everywhere, and you can do crazier things). And various other programs have their own $*PATH variables.
On a related note, when I have experimented with designing a typed version of FilePath, one of the things I wanted to distinguish in the types is exactly this thing about "relative to something specific" (eg relative to "/" or ".") vs "relative to something not yet specified". Another terminology might be "complete" and "incomplete". The OS file manipulation functions would only work on complete filepaths.
I like this distinction. Regardless of the settlement of "" vs "./", it is helpful to distinguish "paths being built" (and therefore potentially invalid) from "real paths" anchored to the file system. -- Live well, ~wren
participants (12)
-
Ben Moseley
-
Brandon S. Allbery KF8NH
-
Bulat Ziganshin
-
Duncan Coutts
-
Duncan Coutts
-
Edward Kmett
-
Felipe Lessa
-
Malcolm Wallace
-
Neil Mitchell
-
Nicolas Pouillard
-
Simon Marlow
-
wren ng thornton