Boost logo

Boost :

From: Beman Dawes (bdawes_at_[hidden])
Date: 2003-08-11 11:04:24


At 07:39 PM 8/10/2003, David Abrahams wrote:

>Beman Dawes <bdawes_at_[hidden]> writes:
>
>> 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.
>
>I really think you have to do better than burying it in the returns
>clause of a single function's docs. The term is used all over the
>library docs.

I've added "complete path" and "relative path" to the Definitions, so
readers will get introduced to the terms much earlier. Also added a FAQ
entry to address the "why isn't it called absolute" questions.

To address some of your other comments, I also changed to tutorial to no
longer use a namespace alias, and to introduce the concept of canonical
form. The tree/root/branch/leaf naming metaphor is now mentioned in several
places early on. The organizational structure of "lexical operations in
path.hpp, filesystem operations in operations.hpp" is presented much
earlier.

>Oh, and initial_directory points nowhere in operations.html: it's
>"initial_path".

Fixed. Also fixed in path.htm.

>> 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.
>
>I could accept the idea that some of the naming choices were
>neccessary, but when you add the choice of "basename" into the mix,
>which flatly contradicts existing practice, it gives the impression of
>being arbitrarily inventive.

I'm not enamored with "basename". I'd like to hear from Vladimir on that,
however, as those functions were contributed by him.

>> IIRC, the idea that is_absolute( "/foo" ) was false on some
>> operating systems was impeded by long-held beliefs.
>
>Err, let's see... strings can be implicitly converted to paths, and
>the implicit conversion treats the string as a "portable generic path
>format", right? So when is "/foo" not absolute/complete? Is not foo
>the name of the root? Oh, after much crawling backwards through the
>docs, I see what has been done here... I suppose it's needless to
>say, but I would've chosen a different approach. The idea that
>is_complete(path(some_string)) returns different values on different
>systems undermines the notion that paths are portable and generic.

The design attempts to balance the needs of those who wish to write
portable programs and would prefer totally generic formats, with those who
need to interact with users, and thus require native formats.

>If I were king, the portable, generic version of windows-native
>"c:/foo" would be "/c/foo" and the portable generic version of
>windows-native "/foo" would be *current_path().begin()/"foo". Is
>there a reason that approach was rejected?

Yes, it had five or six different problems IIRC, although some of them can
be fixed by adding additional syntax. For example, the ambiguity in
"/c/foo" - is it a relative path starting with a directory named "c" or a
complete path to the c drive - can be dealt with via additional syntax.

Early implementations of the library used a lot more inventions for design
aspects like the generic path grammar. As time went on many of them were
removed because they just didn't work well in actual code.

>...
>What do you mean by semantic portability? Isn't it undermined by the
>variability of path("/foo").is_complete()?

Yes, but that gets balanced against the other design goals.

>...
>>
>> 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.
>
>I don't think I understand what you're saying, sorry. Could you be
>more specific?

In some systems, what looks like a file name in a call like open( "foo" )
is actually a key that gets mapped by the operating system to the actual
filename. It is an example (generation data sets and partitioned datasets
are other examples) of really interesting ideas from non-Windows/non-POSIX
operating systems which ultimately were not included in the filesystem
library design.

It was mentioned as an example where, yes, other API's are a great source
of ideas, but were not included in the interest of keeping the filesystem
library design reasonably simple.

>> >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
>> is_empty_file(ph) and is_empty_directory(ph), but they didn't work
>> out in practice, and we changed to a simpler set of non-compound
>> functions. Remember that the library was in private use for quite a
>> while before the public review, and we got to see what worked and
>> what didn't. Compound conditional functions definitely fell in the
>> "didn't" category.
>
>It's easy for people that use a library in private for a long while as
>it evolves to become comfortable with its conventions and
>philosophy. That doesn't mean it will be approachable to people who
>haven't seen it before.

Yes, I've seen that many times. What happened with the filesystem library
however was the reverse. Over time, it became obvious that some of the
initial conventions and philosophy's didn't work well in practice and I
became less comfortable with them. There was then a long period of
simplification resulting in a more basic library that seems to work well in
practice.

>Regardless, I still think the empty/is_empty thing is very confusable.
>
>void f(path p)
>{
> if (p.is_empty()) // whoops, syntax error -- how do I fix it?

Yes, that is very deliberate. Thomas Witt pointed out that by using
somewhat different names, such coding errors turn what otherwise would be a
silent runtime error into a noisy compile-time error.

> {
> ... // could be p.empty() or is_empty(p)
> // but the two predicates mean completely
> } // different things
>}

Yes, and hopefully the compile error will cause the user to look at the
docs to determine which is which.

By the way, early versions of path didn't supply path::empty(). That caused
complaints that people had to write p.string().empty(), which was seen as
too convoluted.

Thanks for all the comments. Hopefully the documentation changes have
addresses the bulk of them.

--Beman


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk