Boost logo

Boost :

From: Carlo Wood (carlo_at_[hidden])
Date: 2004-09-02 08:51:43

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

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 "" 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 "", 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("", &fs::native_check);

Then, in order to get that behaviour, one would have
to explicitely specify it:

if (fs::exists(ap / fs::native_path("", &fs::native_check)))

I don't think that is different for the current implementation with
just fs::path.

Carlo Wood <carlo_at_[hidden]>

Boost list run by bdawes at, gregod at, cpdaniel at, john at