[m-rev.] for review: library changes for `mmc --make' on Windows

Simon Taylor stayl at cs.mu.OZ.AU
Sun Jul 20 01:28:59 AEST 2003


On 15-Jul-2003, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> On 15-Jul-2003, Simon Taylor <stayl at cs.mu.OZ.AU> wrote:
> > On 18-Jun-2003, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> > > On 15-Jun-2003, Simon Taylor <stayl at cs.mu.OZ.AU> wrote:
> > > > +	% Make the given directory, and all parent directories.
> > > > +	% This will also succeed if the directory already exists
> > > > +	% and is readable and writable by the current user.
> > > > +:- pred dir__make_directory(string, io__res, io__state, io__state).
> > > > +:- mode dir__make_directory(in, out, di, uo) is det.
> > > 
> > > This functionality is a bit too high-level.  While I agree that this
> > > functionality is useful, if we're going to add this, then I think
> > > we should also add a procedure to just make a single directory,
> > > without attempting to make any of the parent directories.
> > > 
> > > [For the .NET CLI, I think you can create a directory without creating
> > > all the subdirectories using "(new System.IO.DirectoryInfo(path)).Create();".]
> > 
> > When is this useful?
> 
> Whenever your software is designed so that some other part of the system
> is responsible for creating the parent directories; in such cases,
> non-existence of the parent directory could indicate a serious
> installation problem that ought to be brought to the attention
> of the user.
 
This could be done using io__check_file_accessibility.

> Also, the simpler functionality will be more efficient on many systems;
> this may be important when using network file systems, especially if you
> are using mkdir for locking purposes.

OK. I've added dir.make_single_directory.

> > > > +:- pragma foreign_proc("C#",
> > > > +	dir__split_name_dotnet(FileName::in, DirName::out, BaseName::out),
> > > > +	[may_call_mercury, promise_pure, thread_safe],
> > > > +"
> > > > +	try {
> > > > +		DirName = System.IO.Path.GetDirectoryName(FileName);
> > > > +		if (DirName == null) {
> > > > +			SUCCESS_INDICATOR = false;
> > > > +		} else if (DirName == System.String.Empty) {
> > > > +			SUCCESS_INDICATOR = true;
> > > > +			DirName = mercury.dir.mercury_code.ML_this_directory();
> > > > +			BaseName = FileName;
> > > > +		} else {
> > > > +			BaseName = System.IO.Path.GetFileName(FileName);
> > > > +			SUCCESS_INDICATOR = (BaseName != null);
> > > > +		}
> > > > +	} catch (System.Exception e) {
> > > > +		SUCCESS_INDICATOR = false;
> > > > +	}
> > > > +").
> > > 
> > > Is this really pure?
> > > 
> > > For example, 
> > 
> > ?
> 
> What I meant to say was, does it examine the file system?
> Or does it depend on the system's notion of current directory or
> current drive, which might be changed during the execution of
> the program?

It doesn't.

> > > > +:- pred is_root_directory(list(char)::in) is semidet.
> > > > +is_root_directory(FileName) :-
> > > 
> > > It would help to document what this is supposed to do for corner cases
> > > such as "C:".
> > 
> > C: is a relative path, so that's clearly not a root directory.
> 
> Well, "\foo\bar", which you said above is an absolute directory, is also
> a relative path (it is relative to the current drive).  So this business
> about root directories and absolute directories is not very clear ;-)

I've exported and documented a version of this predicate.
 
> > > > +:- type io__access_type
> > > > +	--->	read
> > > > +	;	write
> > > > +	;	execute
> > > > +	.
> > > > +
> > > > +:- pred io__check_file_accessibility(string, list(access_type),
> > > > +		io__res, io__state, io__state).
> > > 
> > > Shouldn't that be a set(access_type)?
> > 
> > It could be, but it really doesn't matter.
> 
> In that case, the documentation should make it clear that the order
> and multiplicity of elements in the list is not important.
 
Done.

> > > Why are there three different .exp* files for this test case?
> > > Two I can understand, one for Windows-style paths and one for
> > > Unix-style paths, but why the third?
> > > Could you post a diff of the two different Windows-style versions?
> > 
> > The difference is only in trailing directory separators on directories --
> > the .NET CLI strips them, my code doesn't. Given that in some circumstances
> > trailing separators are significant (C: vs C:\), I think it's better not
> > to try to strip them.
> 
> IMHO the Mercury standard library routines for manipulating paths
> should not behave differently on the same (Windows) platform depending
> on whether you're compiling to .NET or not.  That would be a recipe
> for portability problems.  I think it would be better to pick one
> meaning and stick with it, even if that requires more implementation effort.

Done.

> > library/exception.m:
> ...
> > 	Add predicates try_det, try_io_det and try_store_det,
> > 	which only have one mode so they are more convenient
> > 	to pass to promise_only solution.
> 
> That part of the log message is no longer valid.

I decided to leave these -- I've wanted them often enough.
 
> > diff -u library/exception.m library/exception.m
> > --- library/exception.m
> > +++ library/exception.m
> > +:- pred use(T).
> > +:- mode use(in) is semidet.
> > +
> > +:- pragma foreign_proc("C",
> > +	use(_T::in),
> > +	[will_not_call_mercury, promise_pure, thread_safe],
> > +	"SUCCESS_INDICATOR = MR_TRUE;").
> > +:- pragma foreign_proc("C#",
> > +	use(_T::in),
> > +	[will_not_call_mercury, promise_pure, thread_safe],
> > +	"SUCCESS_INDICATOR = true;").
> > +:- pragma foreign_proc("Java",
> > +	use(_T::in),
> > +	[will_not_call_mercury, promise_pure, thread_safe],
> > +	"SUCCESS_INDICATOR = true;").
> 
> Semidet Java foreign code is currently not supported.  So the Java
> foreign_proc here should be commented out or deleted.
> 
> But use/1 could be implemented in ordinary Mercury code as
> 
> 	:- pragma no_inline(use/1).
> 	use(_).

That won't work if unused argument elimination is enabled.
 
> Still, regardless of whether use/1 is defined by Mercury clauses
> or as a foreign proc, calling use/1 in this way is not sufficient to
> guarantee that future Mercury compilers will call Cleanup.  For example,
> if the call to finally happens to be wrapped up inside some code which
> catches exceptions but does not examine which exception was caught,
> a clever compiler might reason that it doesn't make any difference
> whether rethrow/1 or error/1 is called, and that therefore there is
> no need to call use/1.  Admittedly it will be a long time before the
> Mercury compiler is that clever, but still :)
> Declaring use/1 "impure" would be a bit safer.

Done.

Simon.
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list