From: Antonio Menezes Leitao
Subject: open in SBCL
Date: 
Message-ID: <pan.2004.04.29.16.53.08.823551@evaluator.pt>
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.

From: ·········@random-state.net
Subject: Re: open in SBCL
Date: 
Message-ID: <c6rgpc$8on29$1@midnight.cs.hut.fi>
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
From: Antonio Menezes Leitao
Subject: Re: open in SBCL
Date: 
Message-ID: <pan.2004.04.29.23.41.26.202560@evaluator.pt>
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.
From: Christopher C. Stacy
Subject: files/pathname system [Re: open in SBCL]
Date: 
Message-ID: <uvfjg4qwv.fsf_-_@news.dtpq.com>
>>>>> 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.
From: Antonio Menezes Leitao
Subject: Re: files/pathname system [Re: open in SBCL]
Date: 
Message-ID: <pan.2004.05.01.12.13.52.945854@evaluator.pt>
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.