|
Boost : |
Subject: Re: [boost] [Filesystem] v3 path separator changes
From: Alexander Lamaison (awl03_at_[hidden])
Date: 2013-03-24 14:03:06
Rob Stewart <robertstewart_at_[hidden]> writes:
> On Mar 23, 2013, at 12:13 PM, Alexander Lamaison <awl03_at_[hidden]> wrote:
>
>> Beman Dawes <bdawes_at_[hidden]> writes:
>>
>>> On Sat, Mar 16, 2013 at 12:54 PM, Alexander Lamaison
>>> <awl03_at_[hidden]> wrote:
>>>>
>>>> I'm manipulating Unix paths for use over SFTP, but doing so on Windows.
>>>> For instance I might want to append "c" to the Unix path "/a/b".
>>>>
>>>> path p("/a/b");
>>>> p /= "c";
>>>> cout << p.string();
>>>>
>>>> In version 2 this would output "/a/b/c" but now it produces "/a/b\c".
>>>> Why the breaking change?
>>>
>>> IIRC, it was partially requests from users and partially the
>>> realization that most users want platform independent syntax but
>>> platform dependent semantics.
>>
>> In that case I'd expect it to output "\a\b\c". I can't think of a
>> reason why mixed slashes would ever be the right answer. It's the
>> worst of both worlds.
>
> You're expecting this line
>
> path p("/a/b");
>
> to parse your string into "a" / "b" when it merely stores the string
> as you gave it.
That's not true. It does parse the string and recognises "a" and "b" as
separate segments of the path. If it didn't, iteration would return
"a/b" followed by "c". I wrote a small program (included at the end) to
prove this. Here is the output:
Enter path:
a/b
string(): a/b
generic_string(): a/b
native(): a/b
Segments:
"a"
"b"
Enter path:
a\b
string(): a\b
generic_string(): a/b
native(): a\b
Segments:
"a"
"b"
Enter path:
a/b\c
string(): a/b\c
generic_string(): a/b/c
native(): a/b\c
Segments:
"a"
"b"
"c"
> Otherwise, when you add this line
>
> p /= "c";
>
> you expect the previous separator to be used rather than the native
> separator it uses.
I expect the path to abstract over the separators used and, when asked
for the path as a string, return something consistent. It doesn't
matter if that means always using the native separator, as long as it
doesn't use both.
>> But, the biggest issue is that the change wasn't documented. The
>> docs make a big deal of the change from templated paths to a single
>> path class, but make no mention of this, more significant,
>> difference.
>
> I can't imagine that Beman would reject a documentation patch.
I'll fix the documentation once I understand the reasoning.
>>> If you would rather continue to use operator /= then change the output to
>>>
>>> cout << p.generic_string();
>>
>> I've since discovered this string/generic_string/native triplet. I
>> don't think it's the right solution. string() should either return
>> the generic string or the native string. What it returns at the
>> moment is confusing and not very useful. Or is there a use-case I'm
>> not seeing.
>
> string() is returning the contents, as you instructed path to form
> it. Calling generic_string() means parse the contents and ensure all
> separators follow the generic syntax.
Constructing a path from "a/b" isn't an instruction to the library to
construct a path with forward slashes. It's an instruction to create a
path abstraction with two segments, the first "a" and the second "b".
Separators shouldn't even come into it until a string representation of
the path is requested, and the string conversion methods should make
explicit what separator to use: generic or native.
> To do what you want would require path to be modal.
I don't undestand what you mean here.
> Marking it, in this case, to do everything in the generic format first
> would have given the behavior you wanted. However, there is no such
> modality. / appends with the native separator. Construction from a
> string, or appending one, merely stores the supplied string. When you
> want a specific format after mixing those operations, call
> generic_string() or native_string().
Again, this isn't true. / appends a segment. Separators are irrevant
to a path abstraction. In version 2 this was the case. v3 muddles
it by giving seperators extra significance.
Alex
#define BOOST_FILESYSTEM_VERSION 3
#include <boost/filesystem/path.hpp>
#include <iostream>
#include <string>
using boost::filesystem::path;
using std::cin;
using std::cout;
using std::wcout;
using std::endl;
using std::string;
int main()
{
for (;;)
{
cout << "Enter path: " << endl;
string path_string;
cin >> path_string;
path p(path_string);
cout << "string(): " << p.string() << endl;
cout << "generic_string(): " << p.generic_string() << endl;
cout << "native(): ";
wcout << p.native();
cout << endl;
cout << "Segments: " << endl;
path::iterator i = p.begin();
while (i != p.end())
{
cout << "\t" << *i++ << endl;
}
cout << endl;
}
return 0;
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk