
On Wed, Sep 01, 2004 at 02:20:29PM -0400, Beman Dawes wrote:
At 01:53 PM 8/30/2004, Carlo Wood wrote:
My idea on this was (and still is) that it is possible to convert a relative path to an absolute path (automatically) by adding an absolute path object reference to the relative path object.
Yes, as long as you know the absolute path reference. Is the absolute path reference known for all operating systems? I'm not sure about that. For example, there have been multi-rooted systems that didn't have a concept of "current drive". How would that work?
What I mean is that in practical cases a relative path will relative to some directory known to the developer, most likely one that he even reserved a variable for. In other words, in *most* cases there is a relationship between 'relative paths' and 'absolute paths' such that there belongs exactly one 'absolute path' to each 'relative path' (not the other way around, one 'absolute path' can be used by many 'relative paths'). Because this will be the case in over 99% or so cases, it makes sense to add special support for it by adding an 'absolute path' member to the 'relative path' class. This member then can be initialized to refer to an 'absolute path' object (defined by the user). For example: fs::absolute_path ap; fs::relative_path rp(ap); // Tie to 'ap'. ap = "/c/cygwin"; // Set or change it. rp = "foo"; // Now indirectly refers to ap / "foo". // The value of rp is still only "foo" though. In the case that the developer does (want to) specify an 'absolute path' that the 'relative path' will be relative to, for example: fs::relative_path rp; // Not tied to anything. Then it indirectly it will be tied to whatever the native system understands to be 'the current directory', if any. And a call to fs::exists(rp) should do the same as it does with the current implementation. PS In the above I used 'absolute_path' for clarity reasona, but in my real proposal that type does not occur. It should be replaced with 'fs::native_path' (but still be assigned an absolute value) with the same consequences.
This should make sense in every application imho.
It makes sense for calling operating system file system functions. It may make no sense at all if the use of the path is for reporting or other path manipulations.
My proposal was, and is, that this extra reference (added to relative_path, see above) will ONLY be used when a relative path needs to be completed because it is passed to a (file) system call. This happens internally in boost::filesystem and, like you said, makes sense. In cases it does not makes sense - it will simply not be done. For example in the case of reporting (ie, calling the 'native_file_string()' method) the same string will be returned as in the current application. It might be useful however to introduce a method complete_native_file_string() that would complete the path before returning the string, in the same way that a fs::exists would complete the path before testing it.
The programs which process the Boost regression test bjam output do a lot of that. Another example is reporting the path name from a filesystem function which throws an exception.
It might actually make sense to print the full path that the system tried to access in that case - but that is debatable.
As a result, you can simply use absolute path types for all those functions that will pass that parameter to a system call.
Don't for get error reporting. While you certainly could report the absolute path rather than the path as given, that would be a step backward IMO.
In the case of fs::exists, you would have only fs::exists(fs::native_path const&) and when calling that with a fs::relative_path - it would get expanded to the absolute path even before entering fs::exists (this expanding is necessary anyway - so why not before you do the actual call?). That way there is always only one function needed.
You lost me. I could see how what you are describing would work for exists( fs::absolute_path const &).
There is no 'fs::absolute_path' in my proposal. The only relationship that I made between (the proposed) fs::native_path and a path being absolute is that any absolute path should be forced to be of the type 'fs::native_path', because essential any absolute path is native in nature. The objection you came with was that by introducing another type (where I see 'fs::native_path' as the addition and 'fs::relative_path' as the most equivalent to the current 'fs::path') that then function prototypes would be exploding in number. For example both fs::exists(fs::native_path const&) and fs::exists(fs::relative_path const&) would be needed according to you. The above paragraph states that the latter is not needed. You can do with _only_ fs::exists(fs::native_path const&). Why? Because the other one would resolve itself; for example, take this code: fs::native_path ap("/c/cygwin"); fs::relative_path rp(ap); if (fs::exists(rp)) ... You'd think that for this case the fs::exists(fs::relative_path const&) is needed but that is not true because any 'relative' path is convertable to 'absolute path'. Implicit conversion would take place and a temporary fs::native_path with value 'ap / rp' would be passed to fs::exists. Hence my claim that the exploding of number of function will not happen.
It seems you are making some kind of assumption regarding the relationship between native paths and absolute paths. That is possible to do for Windows and POSIX, but not for operating systems in general.
I don't think that I am making assumptions. I merely made an observation, an analysis of 'file paths' in general, and came to the conclusion that a relative path in over 99% of practical cases only make sense when it is relative to *something*. Still - the other 1% (or less) is not harmed. You can still just use only fs::relative_path, without the need to tie it to some absolute path, and still just print its value.
Calling fs::exists("foo") would cause the constructor fs::native_path(char const*) to be called, ...
What happens when the app wants "foo" treated as a generic rather than native format?
In the case of "foo" that makes no difference. The reason that fs::native_path(char const*) is called is just because there is no fs::exists(char const*) and also no fs::exists(fs::relative_path const&) The effect however would be the same when those did exist - so there is no need to add them.
A better example might be "foo.bar" on an operating system which uses "." as a directory separator in native formats.
If a string-literal is passed that has a different meaning when treated as a native path, then when it is treated as a generic path, then adding an extra signature for fs::exists won't help, will it? You can't fix that ambiguity without explicitely saying what type you mean. However, I think that the confusion comes from the name 'native_path'... It is NOT my proposal to have the constructors of this type behave any different from what the current implementation is doing (expect when it comes to throwing an exception). In the current implementation, on a system where "." is the native path separator, you would do: fs::path p("foo/bar"); cout << p.native_file_string(); and that would print "foo.bar", right? Then the same is the case when using fs::native_path: fs::native_path p("foo/bar"); cout << p.native_file_string(); Problems would occur when '.' is the path separator and '/' can be used as file characters in both senarios no? You'd also still be able to do fs::native_path p("c:\\Program Files", &fs::native_check); to *actually* get a native check. I was not aware of OS where '.' is path separator, but I suppose that this works? fs::native_path p("foo.bar", &fs::native_check); Then, in order to get that behaviour, one would have to explicitely specify it: if (fs::exists(ap / fs::native_path("foo.bar", &fs::native_check))) I don't think that is different for the current implementation with just fs::path. -- Carlo Wood <carlo@alinoe.com>