Version 1.1 of acs/ac-00205.txt

Unformatted version of acs/ac-00205.txt version 1.1
Other versions for file acs/ac-00205.txt

!standard A.16(1/2)          10-10-22 AC95-00205/01
!class confirmation 10-10-22
!status received no action 10-10-22
!status received 10-07-19
!subject Ada Directories:Directory Separator
!summary
!topic Ada.Directories: Directory separator
!reference A.16
!from Gautier de Montmollin 10-07-13
!keywords directories directory separator
!discussion
First thanks to Adam for reminding me about the subject... Unless I've missed something, I did not find a Directory_Separator function or constant character. For me it would be a great plus to Ada.Directories - even a must. In GNAT's System.OS_Lib, it is defined as
Directory_Separator : constant Character;
This format would the most appropriate to my opinion.
For the moment you need to use system-/compiler-specific hacks, and it is a shame...
***************************************************************
From: Jean-Pierre Rosen Sent: Monday, July 19, 2010 1:33 PM
> For the moment you need to use system-/compiler-specific hacks, and it > is a shame...
Not all OS's have directory separators. For example, on VMS the syntax is: [<directory>]<name>.<ext>
That's why there are operations to join a directory to a file, but no directory separator.
***************************************************************
From: Adam Beneschan Sent: Monday, July 19, 2010 1:57 PM
Worse, the syntax is actually
[<subdirectory>.<subdirectory>.<etc>.<subdirectory>]<name>.<ext>;<version>
which means that depending on the intended use, you may want the Directory_Separator to be '[', '.', or ']'.
***************************************************************
From: Randy Brukardt Sent: Monday, July 19, 2010 2:47 PM
... > First thanks to Adam for reminding me about the subject... > Unless I've missed something, I did not find a Directory_Separator > function or constant character.
You didn't. The omission is purely intentional. As Jean-Pierre noted, not all systems have a directory separator, nor is it always a single character.
> For me it would be a great plus to Ada.Directories - even a must. > In GNAT's System.OS_Lib, it is defined as > > Directory_Separator : constant Character; > > This format would the most appropriate to my opinion.
This wouldn't work for any system that uses multiple characters (recall that even URLs use "//" in one of the positions).
> For the moment you need to use system-/compiler-specific hacks, and it > is a shame...
If you need to use system-specific hacks, you are doing something wrong. All path name construction/destruction is supposed to use the Compose/Simple_Name/Containing_Directory functions. I don't know of any case where you have to do something else (although this combination is not optimal in all cases - which is why Ada 2012 will add package Ada.Directories.Hierarchical_File_Names with a set of additional functions).
What are you doing that those functions are not sufficient such that you need to resort to a hack instead?
***************************************************************
From: Gautier de Montmollin Sent: Monday, July 19, 2010 2:54 PM
> Not all OS's have directory separators. For example, on VMS the syntax is: > [<directory<]<name>.<ext> > > That's why there are operations to join a directory to a file, but no > directory separator.
Aino aino! I used to work with VMS for long. And to me it is an outstanding system. Is it a reason not to have such an useful function ? No! We can well have (translated appropriedly as RM wording):
function Directory_Separator return Character is begin case OS is when Windows => return "\"; when Unix_and_like => return "/"; when VMS => raise Use_Error with "undefined on this system"; end case; end Directory_Separator;
***************************************************************
From: Randy Brukardt Sent: Monday, July 19, 2010 3:35 PM
... > Aino aino! I used to work with VMS for long. And to me it is an > outstanding system. Is it a reason not to have such an useful function > ? No!
Sorry, but the ARG is in the business in providing solutions; commenters need to provide PROBLEMS. Here, you are providing a solution in search of a problem -- you have yet to provide any problem that can't be solved with the existing and new functions of Ada.Directories.
> function Directory_Separator return Character is begin ...
What could this possibly be used for? Let me consider the obvious possibilities:
* You could use it in parsing file names. But that is reinventing the wheel: Ada.Directories provides a set of file name parsing functions. Moreover, those functions will work on a much wider variety of systems than roll-your-own code would.
* You could use it in constructing file names from parts. But Ada.Directories provides function Compose for that purpose (and Ada 2012 will have an additional more flexible Compose function which is less portable but more powerful for Windows and Unix syst ems). Again, using Compose is more portable and is easier than roll-your-own code.
That's pretty much it, as constructing and deconstructing file names is about all that you can do with a file name (other than passing it to Open or Create_Directory or the like, none of which have any use for function Directory_Separator).
So I repeat: please provide a problem that can't be solved with the existing (and new) facilities.
***************************************************************
From: Georg Bauhaus Sent: Tuesday, July 20, 2010 6:25 AM
> !topic Ada.Directories: Directory separator > Directory_Separator : constant Character; > > This format would the most appropriate to my opinion. > For the moment you need to use system-/compiler-specific hacks, and it > is a shame...
But separators in physical path names of external files are file system specific.
URIs OTOH are an attempt at finding a standardized solution to the problem that is less file system specific and includes ways to address file versions, discs, and maybe some other properties of names. Mappings from URIs to external file system naming con ventions are available.
***************************************************************
From: Dmitry A. Kazakov Sent: Tuesday, July 20, 2010 7:35 AM
> But separators in physical path names of external files are file > system specific.
Yes, and there is no obvious reason to know it. If Compose and its counterpart are insufficient/broken, maybe it were better to fix them?
> URIs OTOH are an attempt at finding a standardized solution to the > problem that is less file system specific and includes ways to address > file versions, discs, and maybe some other properties of names. > Mappings from URIs to external file system naming conventions are available.
Why Ada should map to a mapping? The problem is not in separators, it is that Ada.Directory abstraction of the file system hierarchy is poor. It does not abstract OS. It is incapable to support anything but UNIX/POSIX clones. It does not provide basic func tionalities like enumeration of file system roots. How a layer in between could not change this?
***************************************************************
From: Gautier de Montmollin Sent: Tuesday, July 20, 2010 12:47 AM
> What are you doing that those functions are not sufficient such that > you need to resort to a hack instead?
Indeed I thought that the following would not work on Windows (place with "[2]" in the code below). And to my surprise... it works (with GNAT GPL 2010): GNAT understood '/'s correctly, and did the right job on Windows (for instance). So basically my need f or Directory_Separator disappears. You won! But is it a GNAT hidden feature ? Is the code portable to any compiler ? Gautier --
with Ada.Directories, Ada.Text_IO; procedure Path is f: Ada.Text_IO.File_Type; begin Ada.Directories.Create_Path("src/something/"); -- [1] Ada.Text_IO.Create(f, Ada.Text_IO.Out_File, "src/something/file.txt"); -- [2] Ada.Text_IO.Put_Line(f, "Hello"); Ada.Text_IO.Close(f); end Path;
***************************************************************
From: Randy Brukardt Sent: Tuesday, July 20, 2010 1:20 PM
It would take a lot of work for [2] to not be supported, since the underlying Windows functions support this directly. Janus/Ada pretty much passes the name string directly to Windows, and we use this technique all the time (well, without the use of Ada. Directories; most of our code predates it).
My recollection is that the same is true on POSIX (Unix-like) systems.
OTOH, I'd never say portable to any compiler, since there might be some weird OS that doesn't allow something like [2]. The interpretation of file names is implementation-defined (and usually is just whatever the OS provides), so there is no certainty th at it would be supported absolutely everywhere.
If you narrow the universe to Windows and Unix-like systems (including Unix and Linux), I think the answer is yes, it will always be supported, because I can't imagine an implementation going out of its way to support less functionality than the underlyi ng system calls.
***************************************************************
From: Georg Bauhaus Sent: Wednesday, July 21, 2010 7:28 AM
>> URIs OTOH are an attempt at finding a standardized solution to the >> problem > > Why Ada should map to a mapping?
I didn't mean to say that the language should copy the strings of URIs (RFC 3986). Their definition does, however, describe a more inclusive set WRT identifying resources in a uniform way. The standard RFC describes URIs in abstract terms, really. Ada's definition of path composition would not need to be so thin and vague.
Here's the idea: Since Ada.Directories already has both file system operations and file system name operations, why does it not supply abstractions like it does in other standard packages? (We are talking about them all the time, so ...)
As a first enhancement, add types for the names part of package Ada.Directories at least. Like Text_IO operations can have a file parameter or not, operations in Ada.Directories can have them, too, for backwards compatibility. Among other things mentioned below, this will allow programmers to specify representations via 'Write etc. Or they could use Generic_Dispatching_Constructor.
When a type is added to the directory operations part of Ada.Directories (currently String's ...), too, tagged, it will possible for both vendors and programmers to use Ada's type system to implement Ada.Directories style I/O operations in different environments. Not anonymous subtypes of strings establishing yet another language within the language! Example target:
ftp> quote help 214-The following commands are recognized (* =>'s unimplemented).
USER PASS ACCT CWD XCWD CDUP XCUP SMNT QUIT REIN* PORT PASV EPRT EPSV TYPE STRU MODE RETR STOR STOU APPE ALLO* REST RNFR RNTO ABOR DELE MDTM RMD XRMD MKD XMKD PWD XPWD SIZE LIST NLST SITE SYST STAT HELP NOOP FEAT OPTS ADAT AUTH CCC CONF ENC MIC PBSZ PROT
This kind of O-O flexibility is hidden in URIs, and this is why I have mentioned URIs (RFC 3986) as a standard model.
***************************************************************
From: Adam Beneschan Sent: Wednesday, July 21, 2010 10:45 AM
> Indeed I thought that the following would not work on Windows (place > with "[2]" in the code below). And to my surprise... it works (with > GNAT GPL 2010): GNAT understood '/'s correctly, and did the right job > on Windows (for instance).
As Randy pointed out, this works because Windows accepts the / separator as equivalent to \. Actually, I don't think Windows 95 would have understood it, and maybe not Windows 98; Windows NT did, and I think every Windows system starting with Windows 2000. But in any event, GNAT has nothing to do with it.
But Randy's earlier challenge was to show an example where Ada.Directories' functionality wasn't sufficient, and where a separator would be necessary. And that still hasn't been met; instead of this:
> Ada.Directories.Create_Path("src/something/"); -- [1] > Ada.Text_IO.Create(f, Ada.Text_IO.Out_File, > "src/something/file.txt"); -- [2]
wouldn't this work?
declare Directory : constant string := Ada.Directories.Compose ("src", "something"); begin Ada.Directories.Create_Path (Directory); Ada.Text_IO.Create(f, Ada.Text_IO.Out_File, Ada.Directories.Compose (Directory, "file", "txt")); end;
That should work not just on "Unix" and Windows, but on any hierchical file system, including VMS (perhaps the first Compose would return "[.src]something.dir" and the second would move the "something" inside the brackets...). So even if Windows didn't treat / as a directory separator, the need for a Directory_Separator still hasn't been demonstrated.
However, if you're trying to use a string like "src/something/" in your code, that by itself indicates that you're not interested in portability at all, except for portability between two particular categories of OS. Ada.Directories is, I think, intended to provide functionality for programs that are trying to be portable to any system, so putting in functionality that only works for a couple systems isn't really appropriate (even if those couple systems account for the vast majority of systems in use). However, I don't see any reason that a Directory_Separator couldn't be added to Ada.Directories.Information, since the specifications of those packages are allowed to be different for different OS's. But that's not really a language standard issue, since the Information subpackage is not completely defined by the language, and implementors can throw whatever they want in there, I think.
***************************************************************
From: Randy Brukardt Sent: Wednesday, July 21, 2010 12:10 PM
> As Randy pointed out, this works because Windows accepts the / > separator as equivalent to \. Actually, I don't think Windows 95 > would have understood it, and maybe not Windows 98; Windows NT did, > and I think every Windows system starting with Windows 2000. But in > any event, GNAT has nothing to do with it.
To correct Adam's mistake: using '/' in place of '\' was a feature of MS-DOS 2.0 (the first version to support directories) and of course has appeared in every version of MS-DOS and Windows since (for compatibility reasons if no other). As someone who still remembers the thrill of installing an MS-DOS that supported real directories (given that we'd been living without them for years on PCs), this is something that I am quite certain of.
> But Randy's earlier challenge was to show an example where > Ada.Directories' functionality wasn't sufficient, and where a > separator would be necessary. And that still hasn't been met; instead > of this: > > > Ada.Directories.Create_Path("src/something/"); -- [1] > > Ada.Text_IO.Create(f, Ada.Text_IO.Out_File, > > "src/something/file.txt"); -- [2] > > wouldn't this work? > > declare > Directory : constant string := > Ada.Directories.Compose ("src", "something"); > begin > Ada.Directories.Create_Path (Directory); > Ada.Text_IO.Create(f, Ada.Text_IO.Out_File, > Ada.Directories.Compose (Directory, "file", "txt")); > end;
One would surely hope so.
> That should work not just on "Unix" and Windows, but on any hierchical > file system, including VMS (perhaps the first Compose would return > "[.src]something.dir" and the second would move the "something" inside > the brackets...). So even if Windows didn't treat / as a directory > separator, the need for a Directory_Separator still hasn't been > demonstrated. ... > However, I don't see any reason that a Directory_Separator couldn't be > added to Ada.Directories.Information, since the specifications of > those packages are allowed to be different for different OS's. But > that's not really a language standard issue, since the Information > subpackage is not completely defined by the language, and implementors > can throw whatever they want in there, I think.
That's true; the AARM includes suggested packages for Windows and Unix, but they are defined in terms of "at least". I used "at least" to allow for functions dealing with new capabilities added after Windows XP (which was current when those were defined), but of course it could be anything.
Still, Directory_Separator is 180 degrees from the intended usage of the package; it's not for cases where you don't care about portability (in those cases, just roll your own) because it is so limiting on the syntax allowed.
***************************************************************
From: Randy Brukardt Sent: Wednesday, July 21, 2010 12:15 PM
> Example target: ...
Not sure what your point is here. FTP uses Unix-like paths for its file names (that's determined by the RFC, as I recall). So Ada.Directories would work directly for them. I have no idea why the list of commands is relevant - it doesn't have anything to do with file names.
> This kind of O-O flexibility is hidden in URIs, and this is why I have > mentioned URIs (RFC 3986) as a standard model.
Again, I'm not sure what O-O flexibility that you are talking about. I don't see anything here that you can't do with strings; could you expand on what you ae thinking about???
***************************************************************
From: Georg Bauhaus Sent: Thursday, July 22, 2010 10:19 AM
> Again, I'm not sure what O-O flexibility that you are talking about. > I don't > see anything here that you can't do with strings; could you expand on > what you ae thinking about???
The FTP commands are for illustration, just like newer WebDAV commands would be, both representing a well established and a slightly more recent kind of standard hierarchical file storage, respectively: Suppose I want to create a path on a local file system.
P := Compose ("foo", "bar"); Create_Path (P);
Now my program lets users choose where to store hierarchies. It offers FTP storage as well (or WebDAV, ...). And since this use case of storing hierarchies is exactly the same within every hierachical file system ---the same, that's the point---I'd want to write
P := Compose ("foo", "bar"); Create_Path (P); -- On remote FTP server. How?
too. But Ada.Directories is an abstract state machine kind of package for whatever it happens to support as a hierarchical file storage. Every system-dependent characteristic is to be given as a Form string parameter. So looking for a solution to a ubiquitous problem, I'd end up with a strange expectation: a String based I/O sublanguage in parameter values for use with Ada.Directories for pretty standard file stores.
Now suppose the package is made an ADT package and gets a Directory type. Just like in other packages there is File_Type, or Vector, or Map, or Address:
Store : Directory'Class := ...; -- set via config or by user begin P := Compose (Store, "foo", "bar"); Create_Path (Store, "foo", "bar");
Note that there is nothing system-dependent here, it is totally an abstraction guided by standardized properties of, say, FTP---whatever system provides the standard FTP services. Should I have to wait for the OS to provide a layer of abstraction that hides away different kinds of file stores? Have the polymorphic use case be delegated to OS file system path strings? So that I can continue to use only path strings, not tagged types? And have my programs dispatch not on specific type but on specific values of subpaths?
Tcl when it comes to hierachical file names? ;-)
The ellipsis is where to put things that are between system-dependent and perfectly standard expectations: FTP storage is another kind of hierarchical file storage behaving exactly like local storage, as far as the implicit interface of Ada.Directories goes. Make it explicit, with the help of a limited (controlled) type, for example. It is then possible to add FTP credentials to a derived type. Where else could these go? In the Form string? Inserted in a path somewhere?
On the other hand, strings are the easy way out---I'm not sure this is great, though. Sure, it is already established by Ada.Directories.Hierarchical_File_Names and by RM A.16 61/2:
``For example, on a typical Unix system, Create_Path ("/usr/me/my");
would create ...''
I imagine, then, that the next thing programmers expect is that implementations support
Create_Path("ftp://some.server.id/foo/bar")
Because they are used to it in Perl or Python where they do not usually use features similar to Ada's nice subprograms for constructing paths or acting on paths and (typically) having a proper abstraction for things. (The standard RFC on URIs includes notions of the parts of which a URI is composed.)
IMHO, there is a contradiction:
(1) A file name is not a file; this is reflected in Ada, as there is File_Type. (2) A directory name is not a directory; this is not reflected in Ada. (3) A directory entry name is not a directory entry; this is reflected
in Ada, as there is Directory_Entry_Type.
I find (2) to be inconsistent with (1) and (3).
***************************************************************
From: Dmitry A. Kavakov Sent: Thursday, July 22, 2010 1:32 PM
> Now suppose the package is made an ADT package and gets a Directory type. > Just like in other packages there is File_Type, or Vector, or Map, or > Address: > > Store : Directory'Class := ...; -- set via config or by user > begin > P := Compose (Store, "foo", "bar");
Why cannot compose return path? And why not to use "/" instead?
> I imagine, then, that the next thing programmers expect is that > implementations support > > Create_Path("ftp://some.server.id/foo/bar")
FTP_Host (<address>, <user>, <password>) / "foo" / " bar"
Well, there should be more than just "/" or Compose. The syntax should show whether "bar" is a leaf and the result is a complete path or it is only a node.
Same is true for file extensions. They are abstracted away by the MIME types, this is IMO how Ada.Directories should handle them. I.e. instead of literal ".o", Ada.MIME_Types.Object, which would ultimately yield "o" under Linux and "obj" under Windows and VMS.
BTW, IP <address> should be composed in a similar way.
> IMHO, there is a contradiction: > > (1) A file name is not a file; this is reflected in Ada, as there is > File_Type.
What is file name? Semantically neither path nor File_Type are files. They are referential objects.
> (2) A directory name is not a directory; this is not reflected in Ada. > (3) A directory entry name is not a directory entry; this is reflected > in Ada, as there is Directory_Entry_Type. > > I find (2) to be inconsistent with (1) and (3).
Hmm, that is not obvious. IMO it is simpler. Ada.Directories is untyped. That's the problem. This is in contradiction with Ada design, and makes Ada.Directory barely useful. Text_IO had this flaw as well, but that was not so obvious because file paths there were opaque objects, accidentally strings. It is not so in Ada.Directories. Both need to be fixed.
***************************************************************
From: Randy Brukardt Sent: Thursday, July 22, 2010 3:59 PM
> too. But Ada.Directories is an abstract state machine kind of package > for whatever it happens to support as a hierarchical file storage. > Every system-dependent characteristic is to be given as a Form string > parameter. So looking for a solution to a ubiquitous problem, I'd end > up with a strange expectation: a String based I/O sublanguage in > parameter values for use with Ada.Directories for pretty standard file > stores.
Thanks for the explanation. But note that this isn't a "strange expectation". If you plan to use these paths with any of the existing I/O packages (like Text_IO), you'll also need to use a Form parameter. Indeed, the intent is that if you had a hypothetical compiler that supported FTP as a native file system, there would be a form parameter with each call (Open, Create, Create_Path, etc.) in order to select that.
The intent of Ada.Directories is to provide the file name and path mechanisms needed by the Ada I/O packages (Text_IO, Direct_IO, etc.) -- no more, and no less. Unless you have an Ada file system that supports remote file systems (and I think this is unlikely), Ada.Directories isn't trying to support them.
Note that is doesn't help much for Ada.Directories to support such file systems, since the difficult operations are those envolving files (such as Direct_IO.Open). No amount of generalization for Ada.Directories will help that.
> Now suppose the package is made an ADT package and gets a Directory > type. > Just like in other packages there is File_Type, or Vector, or Map, or > Address: > > Store : Directory'Class := ...; -- set via config or by user > begin > P := Compose (Store, "foo", "bar"); > Create_Path (Store, "foo", "bar"); > > Note that there is nothing system-dependent here, it is totally an > abstraction guided by standardized properties of, say, FTP---whatever > system provides the standard FTP services. Should I have to wait for > the OS to provide a layer of abstraction that hides away different > kinds of file stores? Have the polymorphic use case be delegated to > OS file system path strings? So that I can continue to use only path > strings, not tagged types? And have my programs dispatch not on > specific type but on specific values of subpaths?
But this alone does no good, because you can't do anything with the resulting file name. Besides, "Store" here has nothing to do with a directory. It's a file system declaration, which (if it is exists at all) needs to be far more general than just Ada.Directories -- it would have to apply to all of the file system operations (the various I/O packages, directories, etc.)
> Tcl when it comes to hierachical file names? ;-) > > The ellipsis is where to put things that are between > system-dependent and perfectly standard expectations: FTP storage is > another kind of hierarchical file storage behaving exactly like local > storage, as far as the implicit interface of Ada.Directories goes. > Make it explicit, with the help of a limited > (controlled) > type, for example. It is then possible to add FTP credentials to a > derived type. > Where else could these go? In the Form string? Inserted in a path > somewhere?
The model given to us by Ada 83 is that sort of information goes into the Form string. Ada.Directories doesn't try to change that.
... > IMHO, there is a contradiction: > > (1) A file name is not a file; this is reflected in Ada, as there is > File_Type. > (2) A directory name is not a directory; this is not reflected in > Ada. > (3) A directory entry name is not a directory entry; this is reflected > in Ada, as there is Directory_Entry_Type. > > I find (2) to be inconsistent with (1) and (3).
Perhaps, but none of these are intentional "abstractions"; there just mappings to the typical target OS's facilities.
Ada.Directories started life as Claw.Directories, and thus has a strong Windows flavor. (That happened simply because no one else was proposing anything, so I did it myself and started with my best previous work in the area.)
File_Type is the container for a file handle (in both Unix and Windows). A directory entry is a holder for a Windows record type (one that goes all the way back to CP/M). But there is no directory handle. Yes, you can open a directory like a file in both Unix and Windows, but there isn't much that you can do with it once you have it (Unix allows a bit more than Windows, but neither system allows creating new files or directories in a directory identified by a handle). We didn't want to insist on implementing capabilities not present in the most commonly used systems -- thus no directory abstraction.
In any case, what you are looking for is a file system abstraction, because you want it to change the syntax of file names, the identification of roots, the attributes that can be queried, and many other properties beyond simply abstracting a directory. For instance, an FTP file system abstraction would probably need to specify a user account and password to use; this is not something that you would want to repeat for every folder in an FTP site.
This seems like a big change as it would affect all of the I/O packages; adding an optional additional parameter to most of the operations on files and directories. Surely too much for Ada 2012 (it is to be completely finished by February, so nothing significant new can be added at this point -- it takes a year or so to eliminate the integration bugs from new text).
***************************************************************

Questions? Ask the ACAA Technical Agent