At 08:06 PM 8/9/2003, David Abrahams wrote:
As a user of the filesystem library, I am having the experience that
obvious things are hard to find, and the docs are much harder to
understand than they ought to be. The use of creative naming really
gets in the way. For example, the term complete is never defined
anywhere.
It is defined by the is_compler() returns clause.
The closest we come is in the following naming rationale.
is_complete
bool is_complete() const;
Returns: For single-root operating systems,
has_root_directory(). For multi-root operating systems,
has_root_directory() has_root_name().
Naming rationale: The alternate name, is_absolute(), causes
confusion and controversy because on multi-root operating systems
some people believe root_name() should participate in
is_absolute(), and some don't.
I'm sorry if this sounds harsh, but I think the cure for someone being
confused about the term absolute on multi-root OSes is to pick the
definition that allows the term to be meaningful (an absolute path
identifies a specific location, and so must include the root) and *add
a clarifying note or definition for the corner case*, not to pick some
new term which nobody knows about and makes the library hard to
approach.
The library isn't all that large that people can't just read about each
function.
There were lengthy discussions on the list of this and other naming issues
during development, during review, and during the resolution of review
issues. Many people had fairly strong views. IIRC, the idea that
is_absolute( /foo ) was false on some operating systems was impeded by
long-held beliefs. By giving the function an unfamiliar name, people are
forced to actually read the specs instead of just assuming what it does,
and that ends up being a good thing, IMO.
I suppose if we were to discuss the names all over again we would come up
with a different set of names. But unless the new names are markedly
superior to the old names, it would just be churn to change them, and might
be a real step backwards.
--- aside ---
Regarding complete paths, is there any guarantee that they are
canonical? Is foo/bar/../baz reduced to foo/baz?
Yes. That is documented as a postcondition specifying canonical form for
all the functions that modify a path. I've just double checked, and it
doesn't look like any were missed, but let me know if you spot any way to
alter path state that doesn't supply that postcondition.
See
http://java.sun.com/j2se/1.3/docs/api/java/io/File.html#getCanonicalPath()
for an example of the possible semantics. We could learn a lot about
what's useful and broadly implementable by studying the libraries of
Java and/or Python (yes, I realize that the portability of Java ain't
quite what it's cracked up to be).
Yes, I often found other libraries helpful, although many of them offer
syntactic portability rather than semantic portability.
The legacy operating system API's interesting because they sometimes take
different approaches. Sometimes what we think of as a path is just a key
used to find the actual path via some external mapping mechanism.
--- aside ---
The formal description of some of the function semantics leaves
something to be desired. For example, the docs for remove_all say:
unsigned long remove_all( const path ph );
Precondition: !ph.empty()
Postcondition: !exists( ph )
Returns: The number of files and directories removed.
Throws: if ph.empty(). See empty path rationale.
So, what does this do? At first I thought it removed all the
directories along the branch described by ph. I think I'm now
inferring that if ph is a file, it is the same as remove( ph ) and
otherwise it removes all of the files and subdirectories in ph and
then removes ph. A plain English description would help a lot here.
This applies to many other functions in the library also.
Yes, a general prose description for each library would help.
I also have some doubts about the validity of the postcondition, since
another process can come along and create ph again before remove_all
returns. This applies to many other functions in the library also.
The docs really weren't clear enough about postcondition/race-condition
interactions. I've just added a paragraph to
boost-root/libs/filesystem/doc/index.htm#Common_Specifications to make it
clear that postcoditions don't hold if race-conditions exist.
Because of the race-condition problem, the original docs did not specify
postconditions. Someone pointed out how much clearer they because if
postconditions were used, and the docs got converted at that point.
The difference between is_empty(ph) and ph.empty() is too slight, IMO,
for their differing semantics. IMO it's not useful to have one
function which reports both empty files and empty directories - the
implications of the two are much too different.
Early versions of the library did provide the finer granularity of