June 06, 2013
On Thursday, 6 June 2013 at 15:36:17 UTC, Walter Bright wrote:
> On 6/4/2013 11:27 PM, Dylan Knutson wrote:
>> I'd like to open up the idea of Path being an object in std.path. I've submitted
>> a pull (https://github.com/D-Programming-Language/phobos/pull/1333) that adds a
>> Path struct to std.path, "which exposes a much more palatable interface to path
>> string manipulation".
>
>
> I've succumbed to the temptation to do this several times over the years.
>
> I always wind up backing it out and going back to strings.

As another data point: Java 7 introduces new Path and Paths objects:

http://docs.oracle.com/javase/7/docs/api/java/nio/file/Paths.html

So they clearly think using an object(s) for it is useful.

-----

Without even thinking about the API, just using it, all the code I've written in the past couple of weeks looks something like this:

Path p = Paths.get(someDir, someOtherDir);
p = p.subpath(otherPath, p.getNameCount());
Path file = p.resolve(someFile);
print(file.toString());
file.toFile().doSomething();

ie. All my code is converting to/from a Path object purely for dealing with Windows and Posix / vs \ differences and doing sub-paths. Seems a bit pointless when we could just use free functions in my opinion.
June 07, 2013
On Thu, 06 Jun 2013 15:54:24 +0100, Dylan Knutson <tcdknutson@gmail.com> wrote:

> On Thursday, 6 June 2013 at 10:48:54 UTC, Lars T. Kyllingstad wrote:
>> On Thursday, 6 June 2013 at 10:32:36 UTC, Regan Heath wrote:
>>> On Thu, 06 Jun 2013 08:55:50 +0100, Lars T. Kyllingstad <public@kyllingen.net> wrote:
>>>
>>>> On Thursday, 6 June 2013 at 07:05:52 UTC, Lars T. Kyllingstad wrote:
>>>>>
>>>>> [...]
>>>>
>>>> Let me add some more to this.  To justify the addition of such a type, it needs to pull its own weight.  For added value, it could do one or both of the following:
>>>
>>> Does System.IO.DirectoryInfo:
>>> http://msdn.microsoft.com/en-us/library/system.io.directoryinfo.aspx
>>>
>>> Add sufficient value to justify it's existence to your mind?
>>>
>>> vs just having System.IO.Directory:
>>> http://msdn.microsoft.com/en-us/library/system.io.directory.aspx
>>
>> They add great value, but that is a completely different discussion, as these are more similar to std.file.DirEntry.  The added value is mainly in the performance benefits; for example,
>>
>>     if (exists(f) && isFile(f) && timeLastModified(f) < d) ...
>>
>> requires three filesystem lookups (stat() calls), whereas
>>
>>     auto de = dirEntry(f);
>>     if (de.exists && de.isFile && de.timeLastModified < d) ...
>>
>> is just one.
>>
>> I see no such benefit in the proposed Path type.
>
> Path and dirEntry are different modules with different goals to fulfill. I don't think it's appropriate to compare a module whose function is path manipulation with one whose is querying filesystem information.

Yeah, my fault.  I didn't take the time to look at the proposed module in detail.

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
June 07, 2013
On Thursday, 6 June 2013 at 19:29:08 UTC, Jonathan M Davis wrote:
> On Thursday, June 06, 2013 14:38:41 Andrei Alexandrescu wrote:
>> On 6/6/13 2:13 PM, Jonathan M Davis wrote:
>> >> An example of a strong justification for a redo is, for example,
>> >> conversion
>> >> to use ranges. std.zip needs that treatment.
>> > 
>> > Agreed.
>> 
>> Key to success for Path: somehow get it on the ranges bandwagon :o).
>
> LOL. Well, given that strings are _already_ ranges, that wouldn't help it
> anywhere near as much as it does with other cases of code breakage, since
> std.path is already quite range-ready.
>
> - Jonathan M Davis

Something I wanted to add:

I think using string as the main form of representation for a path is fine.

However, there are times where it is convenient to be able to explode a path into a structure, where each part is clearly separate from the next. This makes it easy to do certain otherwise hard to do operations. eg:

Change:
C:\Users\Monarch\Docs\MyFile.txt
to
D:\Users\Monarch\MyFile.txt

Regexes are fun and all, but they do come with their own complications, and pitfalls. And they *do* require efforts to write. Or use the existing interface. It works, I won't argue agains it, but I do find times where it is kind of clunky.

I'd be in favor of having a "Path" object, if only for being able to help in the construction or modification of string paths.

For example, I imagine something as:
string oldPath = `C:\Users\Monarch\Docs\MyFile.txt`:
Path   myPath  = Path(oldPath);
myPath.drive = 'D';
myPath.folders = myPath.folders[0 .. $ - 1];
string newPath = myPath.build;

I think it would be useful to have that. None of the existing interfaces change. It's just an optional tool that I think would be convenient.

--------

If I may present an analogy: C deals with "time" using the arithmetic "time_t" primitive. It works, is mostly convenient, and is the standard API. Still, C also proposes the "struct tm", which is a time, exploded into year/month/day/hours/min/sec.

You can do nothing with this type, except, well read and write to it, and convert it back to/from time_t. Yet, is has its uses, if only being presented in a way that might be more natural to manipulate. And that is reason enough for its existence.
June 07, 2013
On 6/7/13 1:04 PM, monarch_dodra wrote:
> I think using string as the main form of representation for a path is fine.
>
> However, there are times where it is convenient to be able to explode a
> path into a structure, where each part is clearly separate from the
> next.

Tuple!(
    string, "drive",
    string[], "folders",
    string, "basename",
    string, "extension"
)
parsePath(string path);

string buildPath(string drive, string[] folders, string basename, string extension);


Andrei
June 07, 2013
On Friday, 7 June 2013 at 17:27:16 UTC, Andrei Alexandrescu wrote:
> On 6/7/13 1:04 PM, monarch_dodra wrote:
>> I think using string as the main form of representation for a path is fine.
>>
>> However, there are times where it is convenient to be able to explode a
>> path into a structure, where each part is clearly separate from the
>> next.
>
> Tuple!(
>     string, "drive",
>     string[], "folders",
>     string, "basename",
>     string, "extension"
> )
> parsePath(string path);
>
> string buildPath(string drive, string[] folders, string basename, string extension);
>
>
> Andrei

Yeah. That's pretty much more or less what I was describing. Except "buildPath" would take your (unnamed) tuple type directly.

There'd be also be a "filename" member/ufcs function in there for convenience.

I think that would be a small, but useful, addition to std.path.
June 07, 2013
On 6/7/13 2:10 PM, monarch_dodra wrote:
> On Friday, 7 June 2013 at 17:27:16 UTC, Andrei Alexandrescu wrote:
>> On 6/7/13 1:04 PM, monarch_dodra wrote:
>>> I think using string as the main form of representation for a path is
>>> fine.
>>>
>>> However, there are times where it is convenient to be able to explode a
>>> path into a structure, where each part is clearly separate from the
>>> next.
>>
>> Tuple!(
>> string, "drive",
>> string[], "folders",
>> string, "basename",
>> string, "extension"
>> )
>> parsePath(string path);
>>
>> string buildPath(string drive, string[] folders, string basename,
>> string extension);
>>
>>
>> Andrei
>
> Yeah. That's pretty much more or less what I was describing. Except
> "buildPath" would take your (unnamed) tuple type directly.

No, the version I wrote is more flexible. You get to pass separate arguments to it or just pass a tuple with .expand.

buildPath(parsePath("/bin/sh").expand)

should rebuild "/bin/sh".

> There'd be also be a "filename" member/ufcs function in there for
> convenience.
>
> I think that would be a small, but useful, addition to std.path.

Me 2.


Andrei
June 07, 2013
On Friday, 7 June 2013 at 18:26:42 UTC, Andrei Alexandrescu wrote:
> On 6/7/13 2:10 PM, monarch_dodra wrote:
>> On Friday, 7 June 2013 at 17:27:16 UTC, Andrei Alexandrescu wrote:
>>> On 6/7/13 1:04 PM, monarch_dodra wrote:
>>>> I think using string as the main form of representation for a path is
>>>> fine.
>>>>
>>>> However, there are times where it is convenient to be able to explode a
>>>> path into a structure, where each part is clearly separate from the
>>>> next.
>>>
>>> Tuple!(
>>> string, "drive",
>>> string[], "folders",
>>> string, "basename",
>>> string, "extension"
>>> )
>>> parsePath(string path);
>>>
>>> string buildPath(string drive, string[] folders, string basename,
>>> string extension);
>>>
>>>
>>> Andrei
>>
>> Yeah. That's pretty much more or less what I was describing. Except
>> "buildPath" would take your (unnamed) tuple type directly.
>
> No, the version I wrote is more flexible. You get to pass separate arguments to it or just pass a tuple with .expand.
>
> buildPath(parsePath("/bin/sh").expand)
>
> should rebuild "/bin/sh".
>
>> There'd be also be a "filename" member/ufcs function in there for
>> convenience.
>>
>> I think that would be a small, but useful, addition to std.path.
>
> Me 2.
>
>
> Andrei

An overload for buildPath that took the tuple directly would be good. Typing expand all the time would get tiresome if you were doing lots of this.
June 07, 2013
On 6/6/13 1:02 PM, Michel Fortin wrote:
> and Apple has Case-sensitive HFS+ for OS X and its the default on iOS.

Careful.. While HFS+ can be case sensitive, it's not by default.  Nor is it recommended due to the number of osx applications that just aren't designed with that in mind.

June 07, 2013
On 2013-06-07 20:52:30 +0000, Brad Roberts <braddr@puremagic.com> said:

> On 6/6/13 1:02 PM, Michel Fortin wrote:
>> and Apple has Case-sensitive HFS+ for OS X and its the default on iOS.
> 
> Careful.. While HFS+ can be case sensitive, it's not by default.  Nor is it recommended due to the number of osx applications that just aren't designed with that in mind.

True. But what I meant is that it's the default on iOS, not OS X. (Funnily, if you're running things in the iOS Simulator you'll run on the same file system as OS X, case-sensitive most likely.)

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca/

June 08, 2013
On Friday, 7 June 2013 at 17:27:16 UTC, Andrei Alexandrescu wrote:
> On 6/7/13 1:04 PM, monarch_dodra wrote:
>> I think using string as the main form of representation for a path is fine.
>>
>> However, there are times where it is convenient to be able to explode a
>> path into a structure, where each part is clearly separate from the
>> next.
>
> Tuple!(
>     string, "drive",
>     string[], "folders",
>     string, "basename",
>     string, "extension"
> )
> parsePath(string path);
>
> string buildPath(string drive, string[] folders, string basename, string extension);

This is a good idea.  Not only is it convenient, but as there is a lot of overlap in the work done by the various path decomposition functions, it will also improve performance when you need the results of several of them.

But why stop at the parts you have listed there?  Why not offer every possible decomposition the user could ever want?  It's about the same amount of work, because the number of "split points" you need to find is exactly the same.

Splitting the directory part into separate segments should be optional, since it allocates.

  DecomposedPath!(inout(C)) decompose(inout(C)[] path, bool splitDir = true);

  struct DecomposedPath(C) if (isSomeChar!C)
  {
      C[] driveName;      /// Equal to driveName()
      C[] dirName;        /// Equal to dirName()
      C[] noDriveDir;     /// Equal to dirName().stripDrive()
      C[] rootName;       /// Equal to rootName()
      C[] baseName;       /// Equal to baseName()
      C[] stem;           /// Equal to baseName().stripExtension()
      C[] extension;      /// Equal to extension()

      /// Equal to dirName().pathSplitter().array()  (optional)
      C[][] dirSegments;
  }