Hi everybody,
My initial impression that CMUCL and SBCL would have many things in common
is rapidly disappearing.
According to the Hyperspec (Function open):
An implementation is required to recognize all of the open keyword
options and to do something reasonable in the context of the host
operating system. For example, if a file system does not support
distinct file versions and does not distinguish the notions of deletion
and expunging, :new-version might be treated the same as :rename or
:supersede, and :rename-and-delete might be treated the same as
supersede.
Now, if you open a file for :output, specifying that :if-exists is
:new-version, and the file in fact exists, CLISP, Allegro, Lispworks and
CMUCL (all in Linux) apparently follow the Hyperspec suggestion and
treat :new-version as :supersede.
Contrary to its venerated father (and the explicit recommendation of
the Hyperspec), SBCL (in Linux) apparently prefers to treat :new-version
as :error, meaning that an error is signalled.
Is there a rational to this behaviour?
Thanks,
Antonio Leitao.
Antonio Menezes Leitao <··············@evaluator.pt> wrote:
[I'm swapping the order of quoted bits here, sorry.]
> the Hyperspec), SBCL (in Linux) apparently prefers to treat :new-version
> as :error, meaning that an error is signalled.
Note that CLHS says:
> options and to do something reasonable in the context of the host
> operating system. For example, if a file system does not support
The operative words being "something reasonable"... I at least consider
:error a reasonable behaviour given that the filesystem doesn't do any
versions -- greatly preferable to :supersede and :rename-and-delete (I
don't want my files deleted or overwritten due to silly defaults), and
somewhat preferable to :rename (I don't want my deliberately made
backups overwritten).
The cost of implicit :error is the time required to write :if-exists
:supersede, or whatever the behaviour you want, but the cost of implicit
:supersede is data-loss.
The issue has been hashed over at least a couple of times on the sbcl
lists -- persusal of the archives may produce enlightenment.
Anyways, reading "For example..." as an explicit recommendation sounds
somewhat suspect to me, though you're quite right about SBCL being
against the grain here.
Cheers,
-- Nikodemus
On Thu, 29 Apr 2004 18:16:12 +0000, nikodemus wrote:
> The operative words being "something reasonable"... I at least consider
> :error a reasonable behaviour given that the filesystem doesn't do any
> versions -- greatly preferable to :supersede and :rename-and-delete (I
> don't want my files deleted or overwritten due to silly defaults), and
> somewhat preferable to :rename (I don't want my deliberately made
> backups overwritten).
>
> The cost of implicit :error is the time required to write :if-exists
> :supersede, or whatever the behaviour you want, but the cost of implicit
> :supersede is data-loss.
>
> The issue has been hashed over at least a couple of times on the sbcl
> lists -- persusal of the archives may produce enlightenment.
I followed your suggestion and although I recognize there were some
good points being made, my experience with Lisp Machines is a bit
different.
On the Explorer Lisp Machine we had versions. This was not a
good replacement for a proper CVS but it was helpful, anyway. So I got
this habit of taking advantage of the Operating System facilities and,
whenever it made sense, I would ask for :new-version. But I was aware
that versions were not generally available on Unix (although I remember
that VMS add them) and, as a result, I knew that :new-version
would not be available in other Lisps and would have to be replaced by
something else. If I want to avoid #+ forms (which I do) what are my
options?
- Either choose the conservative solution that works in all
systems (which is :supersede) and forget about versioning on
systems that support it (like the Lisp Machines).
- Or take advantage of the "consensus" that the compiler would translate
:new-version to :supersede in systems that do not support versioning,
thus allowing me to take full advantage of the Lisp Machine file system
and, at the same time, being able to run the code in other systems.
The reason why I think that the translation from :new-version to
:supersede is OK is that when you use :supersede you are in fact creating
a "new version" of some file and setting the old one aside. :new-version
does exactly the same thing but, on file systems that support it, it
allows you to retrieve the older versions.
Note that changing the semantics of the operation is explicitly allowed
by the Hyperspec:
Where necessary to accomodate the file system, an implementation deviate
slightly from the semantics specified here without being disqualified for
consideration as a conforming implementation. If it is utterly impossible
for an implementation to handle some option in a manner similar to what
is specified here, it may simply signal an error.
This, combined with the suggestion in the Hyperspec:
For example, if a file system does not support distinct file versions
[...], :new-version might be treated the same as :rename or :supersede
[...].
gives me the feeling that allowing :new-version to gracefully
"downgrade" to :supersede is the appropriate solution here.
I know that there aren't many file systems nowadays that support
versioning so the :new-version is not doing much actually. However, the
SBCL approach will simply eliminate that option because it will force
programmers to always write :supersede.
Thanks for your comments,
Antonio Leitao.
PS: By the way, after strugling for more than two hours with the most
esoteric bug I have ever seen in my life, I managed to port my Linj
compiler to SBCL 0.8.10. The bug is amusing. Try this:
* (defparameter *f* #'identity)
* (defstruct foo
bar)
* (defun bug ()
(let ((foo-bar *f*))
(if (functionp foo-bar)
(funcall foo-bar 1)
nil)))
* (bug)
Maybe someone will find a shorter example that also triggers the bug.
>>>>> On Fri, 30 Apr 2004 00:41:32 +0100, Antonio Menezes Leitao ("Antonio") writes:
Antonio> On Thu, 29 Apr 2004 18:16:12 +0000, nikodemus wrote:
>> The operative words being "something reasonable"... I at least consider
>> :error a reasonable behaviour given that the filesystem doesn't do any
>> versions -- greatly preferable to :supersede and :rename-and-delete (I
>> don't want my files deleted or overwritten due to silly defaults), and
>> somewhat preferable to :rename (I don't want my deliberately made
>> backups overwritten).
>>
>> The cost of implicit :error is the time required to write :if-exists
>> :supersede, or whatever the behaviour you want, but the cost of implicit
>> :supersede is data-loss.
>>
>> The issue has been hashed over at least a couple of times on the sbcl
>> lists -- persusal of the archives may produce enlightenment.
Antonio> I followed your suggestion and although I recognize there were some
Antonio> good points being made, my experience with Lisp Machines is a bit
Antonio> different.
Antonio> On the Explorer Lisp Machine we had versions. This was not a
Antonio> good replacement for a proper CVS but it was helpful, anyway. So I got
Antonio> this habit of taking advantage of the Operating System facilities and,
Antonio> whenever it made sense, I would ask for :new-version. But I was aware
Antonio> that versions were not generally available on Unix (although I remember
Antonio> that VMS add them) and, as a result, I knew that :new-version
Antonio> would not be available in other Lisps and would have to be replaced by
Antonio> something else. If I want to avoid #+ forms (which I do) what are my
Antonio> options?
Antonio> - Either choose the conservative solution that works in all
Antonio> systems (which is :supersede) and forget about versioning on
Antonio> systems that support it (like the Lisp Machines).
Antonio> - Or take advantage of the "consensus" that the compiler would translate
Antonio> :new-version to :supersede in systems that do not support versioning,
Antonio> thus allowing me to take full advantage of the Lisp Machine file system
Antonio> and, at the same time, being able to run the code in other systems.
The file/pathname stuff in Common Lisp is generally assumed by
programmers, at least initially, to be a portable generic file
access system. After all, it appears to include support for a
variety of different filesystems, and there is some mumbo jumbo
about it doing The Right Thing, for some value of "reasonable".
But what your damn good question about the cross-platform
portability of :NEW-VERSION versus :SUPERSEDE illustrates is
that Common Lisp, per se, doesn't provide the kind of support
that you think it does. To really get that right requires a
bunch of platform-specialized functionality (often provided by
the implementation, but sometimes you have to write it yourself),
along with a slightly more fleshed-out protocol for generically
specifying what you want to happen. Some programmers write their
own libraries to ameleorate these issues. It's very hard to get
it all right, or even to clearly define what problem you're trying
to solve, which in my opinion is why X3J13 sort of punted on it
(I wasn't on the committee though; just a developer.)
The Symbolics implementation of all this stuff was even fancier than
the MIT/LMI/Explorer version. It even went so far as to magically
emulate file versions on Unix, using techniques similar to (but more
reliable than) the file pseudo-versioning feature in GNU Emacs.
It also supported for Unix a uniform wildcard namestring syntax,
knew the difference between versions and types, etc. In general, it tried
to hide the differences between the filesystems on the various platforms,
as well as the access protocols (FTP, NFS, etc.) and make them all
transparently operate as close as possible to the super model file system.
(The native Symbolics file system implemented the super model, pretty
much supporting all possible features!) The Common Lisp file/pathname
system is a very stripped down incomplete take on what the Lisp Machine
did in this area. Note that the setting for all of this was not exactly
the same as today. Lisp Machine hackers were not necessarily so much
interested in porting their applications onto other platforms, as they
were interested in being able to use their LispMs in whatever network
environment was available. It was a world of heterogeneous operating
systems and network protocols in which the various filesystems were
treated by the LispM user as file servers that people might also want
to log in to and do native things. These generic filesystem access
features were (only) part of the reason why the LispM (particularly
the more developed Symbolics version) was the most amazingly powerful
network connectivity tool in the world.
Anyway, getting back to your problem: I guess the workaround is to
encpasulate your calls to OPEN in a function where you can easily
isolate your #+ frobbing and any other platform-specific behaviour.
Your application (that is, this little library you'll write as part
of your application) will have to do the work of recognizing that the
filesystem semantics and user's model of the filesystem are platform-specific.
ANSI Common Lisp only gives you some minimal functionality for dealing
with this area, not the higher-level stuff. This is probably not as
powerful out-of-the-box as you were hoping. At least it's much better
than nothing, which is what most languages provide.
On Sat, 01 May 2004 06:12:17 +0000, Christopher C. Stacy wrote:
[lots of good stuff]
>
> Anyway, getting back to your problem: I guess the workaround is to
> encpasulate your calls to OPEN in a function where you can easily
> isolate your #+ frobbing and any other platform-specific behaviour.
I will also have to define a new 'with-open-file' macro. It's
not hard but it's something that programmers will have to remember. In
practice, I think most people will just write the uglier
(with-open-file (f :direction :output
:if-exists #+sbcl :supersede #-sbcl :new-version)
...)
Even more practical is to acknowlege that the most used file systems do
not support versioning and simply write
(with-open-file (f :direction :output :if-exists :supersede)
...)
That's why I think the SBCL decision will kill :new-version.
I agree that SBCL has the right (and a good argument) to make :new-version
equivalent to :error but, somehow, I get the feeling that it's a decision
that will suprise a lot of people both because they get a different
expectation from the Hyperspec and because they have a different
experience from the other Common Lisp implementations.
Thanks for your comments,
Antonio Leitao.