Yesterday I confused my OS X system badly enough that when I tried to quit the Terminal application using Command-Q, I broke into Macsbug. Which reported that the current application was... Terminal.
I thought Classic was its own rather separate world, but apparently there are more points of contact than seem, well, healthy.
I really should have gotten a screenshot of that.
More lisp application screenshots, fewer tired porn metaphors.
Algorithme also created CORAPS, a lisp application that is used in Belgium to plan the refuelling of nuclear power plants:
ORPHEO is a knowledge modelling tool for the design of large hypertext documents:
It's barely possible that some of the other applications listed here are interesting, despite not having screenshots.
A new version of Franz' open source DNS server, ans, is available.
From the ChangeLog:
Many changes to help w/ case mode issues.
I need to memorize Kent Pitman's recommendation for constructing pathnames:
Certainly when making a file FOO.LISP from another, you should do: (make-pathname :name "FOO" :type "LISP" :version nil :host (pathname-host pathname1 :case :common) :device (pathname-device pathname1 :case :common) :directory (pathname-directory pathname1 :case :common) :case :common) or (make-pathname :name "FOO" :type "LISP" :version nil :defaults pathname1 :case :common)
Actually I already knew this. Well, that is, I knew the first way, but found it so verbose that it felt wrong, even though I knew it was right. I forgot about the second, shorter method using :defaults. It is now my favorite new Lisp idiom.
Kent goes on to say
A good rule of thumb, I claim, is to always use :case :common. I can't stand that it is not the default, but since it is, you must always make it explicit. And don't get lazy about using it on the accessors, or you will compose stupid-looking filenames. The algebra decomposing and recomposing filenames only comes out right if you consistently use :case :common everywhere.
On accessors too!? This, I cannot bear. It's hideous. I will have to live with the fact that I am a lazy, sloppy programmer who chooses to write less portable code than I could.
I remember when I first realized from reading CLTL2 that one should use :case :common, and that under Unix, e.g., one needed to write pathname components with exactly the opposite case of the actual files. It was shocking not only because it was kind of ridiculous, but also because it seemed pretty important for achieving portability and yet I had never heard anyone mention it. Which was, of course, because none of the code I saw, written by people at both the University of Chicago and Northwestern, people who knew lisp very well, actually did that.
Frankly, I don't think it matters very much. I'm satisfied using :case :local and mostly lower case filenames, because, really, that is how at least 99.9% of the machines on the planet do things.
No, I don't find that a very satisfying justification either. It's the Perl mindset, not the typical lisp way of doing things right. But haven't you ever run into a bug in a library or API or language implementation that you knew how to work around, but the bug was so lame and the workaround was so aesthetically offensive that you just couldn't force yourself to write the workaround code?
Mike showed me this, which is not quite what I had in mind when I wrote the error handling code:
I think it's time to look into HTTP 1.1 buffering in AllegroServe. It's just like what we did for FleetXChange at Neodesic, only this time it's not Java.
Today's downtime brought to you by OS X and myself.
lemonodor is hosted on my old G4, which sits in my office. That machine has been running OS X for the last month or so.
A while ago I went through a flurry of OS X hacking. I installed fink and xdarwin. I moved the Users and Applications directories off the too-small root partition. Some of the things I did were wise and carefully considered. Others were rash. And messy.
Anyway, eventually I noticed that Netinfo Manager refused to run. I became worried about progressive, insidious corruption. I decided to nip it in the bud; it was time to back up my stuff and reinstall the operating system.
Fast forward past the new LaCie CD-RW drive catching fire when I plugged it in.
So far it works.
The most important lessons I am taking away from this experience are
I'm pretty sure that if Netinfo Manager stops working again, well, at this point I would just pretend I didn't notice.
P.S. Rainer Joswig found a driver for my Epson Stylus Photo 750 on an Epson France FTP server. I owe him one.
lemonodor was down most of today courtesy of AT&T@Home.
Jon Udell talks a little about opportunities for Lisp, Paul Graham, and .NET.
Paul Graham has done more for the visibility of and positive attention toward Lisp than anyone else in the last five years.
You might be interested in this comp.lang.lisp thread in which Duane Rettig talks a little bit about what Franz' feelings about .NET. Or maybe Dan Barlow's diary entry on the subject (scroll to Feb 6).
In 1988 I went to work at JPL, and again I found myself running rings around other programmers by using Lisp. I did things (like write compilers for little mini-languages) that people using C (there was no C++ at the time) wouldn't even contemplate attempting.
At JPL I encountered an interesting phenomenon. I would have proposals rejected on the grounds that what I was proposing was too hard and couldn't be done, when in fact I knew that what I was proposing was actually quite easy (if one used Lisp). It got so bad that I would actually develop prototypes as part of the proposal writing process just so that I could say, "Not only is this not hard, it has already been done." (It actually got even worse than that, but putting the details on the record would not be healthy for my career.)
I also encountered an astonishing prejudice against Lisp and towards C. Between 1988 and 1991 I worked on the research program that led to the Mars Pathfinder rover. We built three prototype rovers during that time, and I either wrote the code or supervised the person who did on all of them. All three of them were programmed not in Lisp, but in little mini-languages whose compilers were written in Lisp. (The rovers themselves only had 8 bit processors with a few hundred or a few thousand bytes of memory so we couldn't run Lisp directly.)
But when it came time to write the code for Sojourner they wrote it in C. As far as I know the possibility of using the work we had done on the prototypes was never even considered. All I know is that I was never approached about it.
A similar thing happened many years later on a project called Remote Agent (RA), which was a flight experiment to demonstrate an autonomous control system for a spacecraft. (http://ic.arc.nasa.gov/ic/projects/remote-agent/) At the beginning of the project we had a lot of prototype code written in Lisp, so it seemed natural to me to just fly Lisp aborad the spacecraft. The resistance to this idea was tremendous and unrelenting. Fortunately, we resisted successfully. I say fortunately, because at one point an attempt was made to port part of the code (the planner) to C++. Afer a year that effort had to be abandoned. On the basis of that experience I think it's safe to say that if we hadn't used Lisp the Remote Agent would not have happend.
Nonetheless, it was not an unconditional victory. RA was part of the first New Millennium mission, which was the flagship for Dan Goldin's new "better, faster, cheaper" initiative. As a result we were given a budget and schedule that everyone knew up front was impossibly tight. When the inevitable schedule and budget slips hit the fan, Lisp became the scapegoat. The software integration engineer was asked at a very prominent review board hearing (attended by over 100 people) what was the most significant factor causing the schedule slips. His reply: Lisp. As a result, RA was down-graded from the mainline flight software to a two-day flight experiment.
That was pretty much the end of Lisp at JPL. On my next project I tried again to sell it, but the political damage done by the Remote Agent experience was insurmountable. Finally, out of frustration, I quit JPL and went to work for Google.
That stock movable type template was beautiful, wasn't it?
For the past year I've been doing 100% of my lisp programming inside emacs. Since it took me some time and effort to customize emacs for that task, and the payoff was significant, I figured I would share the stuff in my .emacs that makes me more productive. I'm no elisp hacker; I accumulated all of this code from people who know more than I did. Now I'm just passing it on.
This is what I have in my .emacs on my Windows PC, where I use ACL and GNU emacs for Windows with Franz' emacs-lisp interface. (I use ilisp under Linux with cmucl sometimes, but I barely know how to use it. You should be helping me.)
Big deal, everyone has this.
(load "c:/program files/acl61/eli/fi-site-init") (setq fi:common-lisp-image-name "c:/program files/acl61/alisp")
Press a key while the cursor is on a Common Lisp function, macro, variable, constant or special operator, and instantly see the official documentation of the symbol in the HyperSpec. You need this.
There are several different HyperSpec lookup interfaces for emacs (the ilisp distribution has all the major ones). I just happen to use hyperspec-naggum.el because it's the one I know. Whichever you choose, just put it in your emacs site-lisp directory.
So that I don't need to have net access while coding, I downloaded and installed a local copy of the Hyperspec from Xanalys (see the link at the bottom of the page to download). You can put it anywhere you want on your machine, you just have to set the common-lisp-hyperspec-root variable to point to it.
I had to install a small helper application called shelex.exe so that emacs could open URLs on my PC. For emacs 20.4 and later you shouldn't need to, but check the emacs for Windows FAQ for details.
Finally, I bind the F1 key to hyperspec-lookup in both the lisp listener and lisp editing buffers.
;; Look up Common Lisp symbols in the Hyperspec. (load-library "hyperspec-naggum") (setq common-lisp-hyperspec-root "file://c:/HyperSpec/") ;; From the GNU Emacs for NT homepage ;; <http://www.cs.washington.edu/homes/voelker/ntemacs.html#browse-url> (defvar shell-execute-helper "shelex.exe") (defun shell-execute-url (url &optional new-window) "Invoke the shell-execute-helper program to call ShellExecute and launch or re-direct a web browser on the specified url." (interactive "sURL: ") (call-process shell-execute-helper nil nil nil url)) (setq browse-url-browser-function 'shell-execute-url) ;; Add F1 to do a hyperspec lookup. (add-hook 'fi:lisp-listener-mode-hook (function (lambda () (local-set-key [f1] 'hyperspec-lookup)))) (add-hook 'fi:common-lisp-mode-hook (function (lambda () (local-set-key [f1] 'hyperspec-lookup))))
I don't like the way that emacs indents if expressions, with the then clause indented more than the else clause. I want them indented the same distance, which is how the FRED editor in MCL does it, and the way I am used to. Erik Naggum helped me get this right.
I spend a lot of time editing RAPs code, which is an s-expr based language, so I put emacs into lisp mode when I edit a *.raps file, and I also customize the indentation of some RAP forms a little bit.
;; Indent IF the way MCL does it. ;; From Erik Naggum, see <http://x23.deja.com/getdoc.xp?AN=495562135> (put 'if 'lisp-indent-function 1) (put 'if 'fi:lisp-indent-hook 1) ;; From Jim Firby, for indenting RAPs. (setq auto-mode-alist (cons '("\\.raps" . common-lisp-mode) auto-mode-alist)) (put 'define-rap 'lisp-indent-function 1) (put 'define-rap 'fi:lisp-indent-hook 1) (put 'define-primitive-event 'lisp-indent-function 1) (put 'define-primitive-event 'fi:lisp-indent-hook 1) (put 'define-rap-function 'lisp-indent-function 1) (put 'define-rap-function 'fi:lisp-indent-hook 1) (put 'define-memory-rule 'lisp-indent-function 1) (put 'define-memory-rule 'fi:lisp-indent-hook 1)
My old co-worker from Neodesic, Jim Bullard, shared this code to turn on maximum syntax highlighting. Don't worry, it's not very maximum.
;; From Jim Bullard, for automatically fontifying Java buffers ;; (and others). (cond ((fboundp 'global-font-lock-mode) (global-font-lock-mode t) (setq font-lock-maximum-decoration t)))
This is the most obscure, and second most useful (after hyperspec access) emacs customization I have.
MCL and ilisp both display function argument lists in the editor minibuffer when you type a function call followed by a space, e.g., "(print ". It's incredibly handy. Unfortunately, Franz' emacs-lisp interface doesn't include this functionality.
Luckily I ran across some code written by Simon Andras, called elidoc, that adds this to eli. The only place that I know it is available is in the archive of the ACL mailing list. Download it from ftp://ftp.franz.com/pub/misc/allegro-cl-log, and search the 3.5 MB file for "elidoc". The first message you find will be Andras' from February 2000. Extract the elisp code from his message and save it in a file named elidoc.el in your site-lisp directory.
(autoload 'turn-on-elidoc-mode "elidoc" nil t) (add-hook 'fi:common-lisp-mode-hook 'turn-on-elidoc-mode) (add-hook 'fi:inferior-common-lisp-mode-hook 'turn-on-elidoc-mode) (add-hook 'fi:lisp-listener-mode-hook 'turn-on-elidoc-mode)
Somewhere along the line I became used to using control-up arrow and control-down arrow to navigate through command histories. This bit of code makes that work in the lisp listener.
;; From Will Fitzgerald. Makes C-up and C-down act like C-c C-p ;; and C-c C-n respectively, in a lisp interaction buffer. (add-hook 'fi:lisp-listener-mode-hook (function (lambda () (local-set-key [C-up] 'fi:pop-input) (local-set-key [C-down] 'fi:push-input))))
Which reminds me. ilisp would not aggravate me half as much if I could navigate through previous commands without moving the point, which is what fi:pop-input and fi:pop-output do. ilisp's comint-previous-prompt and comint-next-prompt suck in comparison. I'm probably missing something obvious.
Thats the stuff I use every day. I hope it helps.
Error: Using package `INET.UTIL.LOG' results in name conflicts for these symbols: WRITE-LOG [condition type: PACKAGE-ERROR]
But it can be so hard to figure out exactly where the source of the conflict is. And I sure am lazy. Hence this horrific hack in which I advise intern:
(defun break-on-intern (sym-name) (flet ((check-intern (this-sym-name &optional package) (declare (ignore package)) (when (equal sym-name this-sym-name) (break)))) (def-fwrapper intern-wrap (sym-name &optional package) (check-intern sym-name) (call-next-fwrapper)) (fwrap 'intern 'intern-breaker 'intern-wrap)))
CL-USER(5): (break-on-intern "WRITE-LOG") #<Function INTERN> CL-USER(6): (load "demo-dev-startup")
Surprisingly, it worked. Though of course in the fresh lisp I started, there was no conflict. Heh.
Alberto Riva announced the release of his CL-ZLIB library, which is a lisp wrapper around the zlib compression library. It runs under ACL6 (windows and linux), though "It should be relatively easy to port it to other platforms".
(Also available from Alberto's page is a lisp wrapper around a subset of the openssl encryption library, and a wrapper around the GD image generation library.)
Michael Parker has released a library that is more or less an implementation of awk in Lisp: CL-AWK
He says "I've been using it on my (sadly) AWK-free lispm, but I've tested it and it works on clisp and Lispworks 4.2 as well."
(defawk checkpass () (BEGIN (setq *FS* ";")) ((/= *NF* 7) (format t "~%line ~D, does not have 7 fields: ~S" *NR* $0)) ((~ $1 #/[^A-Za-z0-9]/) (format t "~%line ~D, nonalphanumeric user id: ~S" *NR* $0)) (($== $2 "") (format t "~%line ~D, no password: ~S" *NR* $0)) ((~ $3 #/[^0-9]/) (format t "~%line ~D, nonnumeric user id: ~S" *NR* $0)) ((~ $4 #/[^0-9]/) (format t "~%line ~D, nonnumeric group id: ~S" *NR* $0)) ((!~ $6 #/^\//) (format t "~%line ~D, invalid login directory: ~S" *NR* $0)) )
They did a great live version of Evil Eye, and beyond a doubt it was great to hear their fuzz sabbath socal stoner rock in person. But my favorite stuff of theirs depends a lot on the production value, and that doesn't come across so well live.
So here's my newest patched version of cmucl's connect-to-inet-socket:
From the comments:
An attempt to rewrite connect-to-inet-socket in such a way that connection attempts that take a long time will not be stuck in the connect(2) system call preventing cmucl from running other lisp threads.
The strategy here is to put the socket in non-blocking mode, and then call connect, which should immediately return. Then there are three cases to handle:
Cases 1 and 2 are simple enough, we just return the socket or signal an error.
In case 3, we call system:wait-until-fd-is-usable to block just the current thread until the socket is writeable (which signals that the connect has finished, one way or the other).
Once wait-until-fd-is-usable returns, we put the socket back into blocking mode and try to determine whether the connect succeeded or failed (and why it failed). I used an approach described at http://cr.yp.to/docs/connect.html, which is attributed to Douglas C. Schmidt and Ken Keys.
I first call getpeername, and if it returns 0 the connect succeeded, otherwise it failed. If it failed, I try to read a single character from the socket. I know it can't work, but it should cause errno set to the real reason for the failure.
If this works, and is robust, I don't see any reason for it not to replace the connect-to-inet-socket from cmucl.
The current CVS version of ILISP has a fix for this. If you want to keep your ILISP version you can replace the file 'hyperspec-naggum.el' with this one: <http://weitz.de/files/hyperspec-naggum.el>. Make sure to set 'common-lisp-hyperspec-symbol-table' to the correct value for your local installation of the CLHS.
ITA Software is the hot company right now that's hiring for the near-mythical "Lisp job". But what if you don't want to sell plane tickets?
As far as I know, the classic email@example.com mailing list is dead, which is unfortunate as it used to be an great resource.
In comp.lang.lisp, Steven Haflich shares what he learned from writing an automatic Lisp job aggregator tool:
Of all the major jobs sites that I scanned in this project, by far the most productive was monster.com. I don't know why, but they seemed always to have a larger number of "interesting" Lisp jobs than the competitors. It is true that a year or two ago there were more jobs than now, but I believe this is more due to general economic conditions than the relevance of Lisp.
(Don't worry, the instant the company I work for starts hiring more Lisp programmers, I'll let you know.)
How is it that I am still learning about cmucl's threading model?
Martin Cracauer says that it's worse than I thought, that threads are "not interruptable at all, even in userland (not systemcall) excecution, unless they yield by themself." Cool.
Me: Well, we don't have to worry as much about Echo not being completely thread safe...
Mike: ...because cmucl doesn't have threads.
It's not actually quite that bad. Echo is almost always blocking on something; there is rarely an extended burst of pure computation that would starve other threads. But maybe we should have looked harder at LispWorks for deployment.
I saw Peaches at the Fireside Bowl once. I think she would have taken off her pants even if it hadn't been 125 degrees in there.
Paul Graham has written an essay about design: Taste For Makers.
"Good design is often strange. Some of the very best work has an uncanny quality: Euler's Formula, Bruegel's Hunters in the Snow, the SR-71, Lisp. They're not just beautiful, but strangely beautiful."
I discovered another terrible bit of code I had written, where my naive expectations of what cmucl would do and the disappointing reality of cmucl's behavior conspired to destroy any semblance of interactivity in Echo.
I was using ext:run-program to run a unix executable. And I gave it a :wait argument of T because, well, I really wanted the program to finish running before I returned a value from my function. And it worked great, except that it completely blocked all lisp threads from running until the other program finished. I sigh.
The problem is in ext:process-wait, which is what ext:run-program uses when :wait is T:
(defun process-wait (proc &optional check-for-stopped) "Wait for PROC to quit running for some reason. Returns PROC." (declare (type process proc)) (loop (case (process-status proc) (:running) (:stopped (when check-for-stopped (return))) (t (when (zerop (car (process-cookie proc))) (return)))) (system:serve-all-events 1)) proc)
(Actually, it seems to me that the call to system:serve-all-events should cause other threads to run, but experimentally I have verified that they don't.)
I basically replaced ext:process-wait with the following code, which makes everything work better:
(mp:process-wait "waiting for exec" #'(lambda () (let ((status (process-status process))) (and (not (eq status :running)) (not (eq status :signaled))))))
Well, that can't help but improve responsiveness of a server that runs external programs constantly, can it? As long as it is correct and safe. Please let it be correct and safe.
cmucl's behavior here probably doesn't count as a bug, but it sure isn't the best one could hope for. I think it was Tim Moore that once said something about trying to decide whether it would be better to rewrite cmucl to be as non-blocking as possible, or to add native thread support. I suppose the right thing to do is... both.
I've hardly used LispWorks, but I know there are people that really like it. Xanalys has just released version 4.2.
Xanalys mentions the following improvements:
All Platforms: Improved documentation, Syntax coloring/highlighting, Windows keys emulation, Improved multithreading in IDE, Toolbars and other improvements in IDE, New CAPI elements: text-input-range, tree-view, tooltip, Extended sockets API, CORBA Object URLs. Win32 and Linux: Foreign parser: FLI generator/header files conversion tool, Improved runtime efficiency. Win32: COM client and server interface and COM browsers, MDI, New CAPI element: docking-layout. Linux and Unix: ODBC interface. Unix: New CAPI elements: progress-bar, toolbar, HP-UX11 support
The Personal Edition ("Now with more generous heap size limit in version 4.2!") is free for downloading.
I feel compelled to point out that MCL isn't the only Lisp in which it's not hard to do real, slick applications.
We wrote a toy domain for DPMA using Microsoft Agent, for some Aibo Research guys from Sony. It uses ACL, using their COM interface to some Visual Basic code that wraps the MS Agent stuff to make it a little easier to use from Lisp.
Here's a screenshot of our Telematics simulator, which is not meant to be a finshed, polished application, just a testbed for using DPMA inside a car. It's a VB application that uses a DLL created with ACL that contains DPMA (phew!).
OK, I promise the run of self-congratulatory postings is officially over.
lemonodor is pleased to announce its new revenue model.
Er wait, no. Actually Rainer Joswig was showing everyone in #lisp why people get excited (worked up, even) about MCL by posting a series of what he called "MCL porn", screen shots of slick-looking MCL applications. Bring on the lickable interfaces!
Here's Noteheads' Igor Engraver:
The MCL IDE, including editing windows, listeners, class browsers, the interface designer, and CLIM (and check out that cinema display!):
Making music with MCL:
The original Dylan programming environment from Apple was an MCL application, as was Apple's SK8 multimedia programming environment (remember when Apple had an Advanced Technology Group?):
Then came something that made my week.
Rainer said "Here is the coolest lisp screenshot I have ever seen. It is a space shuttle simulator, with 3D graphics, speech recognition, and agent technology." And then he pasted a screenshot of the AERCam simulator that I worked on at Neodesic! He doesn't know me and he certainly didn't know I was on IRC; he must have grabbed that screenshot from an old site of mine years ago.
That was so cool.
Here's my old, rudimentary AERCam page (please excuse the chunky graphics; it was 1997, after all). It was a cool system, and at i/net we're still working on the same underlying natural language/robotics control system, DPMA.
[All images courtesy Rainer Joswig; Thanks Rainer.]
The project has just started, and I think it only runs under cmucl at the moment, but the goal is to get it working under all the lisps that run on "modern Unix platforms".
It's not a GUI, it doesn't handle video formats like MPEG or QuickTime or anything, but it looks like an impressively cross-platform way to do 2D & 3D graphics. I'll try it just to see the boids demo.
Edmund Weitz is attempting to organize a "Lisp Cookbook" in the same vein as the Perl Cookbook, which provides solutions to everyday tasks like reading configuration files, or reading a random line from a file.
This could be very useful. There are a lot of common-practice Lisp idioms and techniques that it would be difficult for a new programmer to find out about unless they work directly with more advanced programmers. E.g., how to write variable binding macros that allow declarations.
The development of a cookbook may also motivate some sort of consensus for other problems where there may not be a common solution, or at least discussion of several alternative solutions and how to determine which is most appropriate. E.g., Doing search and replace in sequences, reading telnet-style lines terminated by CR LF, or writing robust TCP server code.
It will be interesting to see where this project is six months from now.
Last year at around this time, Carl and I were driving across the Yucatan in a rented Beetle, looking at Mayan ruins. Uxmal, Kabah, Sayil, Labna, Loltun and Chichen Itza. We also lounged at the beach in Chicxulub, the impact site of the meteorite that killed off the dinosaurs.
I like this photo I took at Labna, it reminds me of an old Piranesi engraving:
A new issue of Free the X3J Thirteen!, Dan Barlow's monthly summary of news from the free Lisp world, is out.
Paul Graham's On Lisp, always in high demand and yet tragically out of print for some time, is now online.
Not that I need it, since I have the real thing. Suckers.
Hm. That there is a fine chair.
Raymond Wiker in comp.lang.lisp pointed out this ebay auction: INTRO TO COMMON LISP SPEECH PATHOLOGY BOOK
Yes, I stole Raymond's subject line.
Xanalys has upgraded their online, publically accessible copy of the HyperSpec from version 4.0 to 5.0 (well, either 5.0 or 6.0; The version comment that is normally in the HTML source is gone).
The new version has some real improvements (format directives and sharpsign reader macros are better indexed), but the URL structure is pretty different, which will break any older HyperSpec lookup code you may be using (E.g. Erik Naggum's hyperspec.el for emacs, or Rainer Joswig's ANSI-CL-HyperSpec for MCL).
Unfortunately, it also means that for now the first link that comes up when you search for "hyperspec" on Google is broken.
This article by Kent Pitman includes more information on the new stuff in 5.0. My favorite is that the filenames are now 8.3 compatible, which supposedly saves a lot of disk space!
Mike is finding bugs in things at an alarming rate.
First, when the following function is put in a file and cmucl's compile-file is called on that file, it causes a compilation error:
(defun foo () (labels ((bar (&optional (a 1)) (bar 0))) (bar 2)))
Error in function COMMON-LISP::ASSERT-ERROR: The assertion (EQ (C::LAMBDA-TAIL-SET C::CALLER) (C::LAMBDA-TAIL-SET (C::LAMBDA-HOME C::CALLEE))) failed.
Word is this may be fixed in the upcoming cmucl 18d release.
Then in ACL 6.1, (rename-file "grammar/old.txt" "grammar/new.txt") actually just changes the name of old.txt to new.txt, when according to the spec it should be doing a little more pathname merging, and try to move grammar/old.txt to grammar/grammar/new.txt.
The workaround is not to use relative directories with rename-file.
Another ACL bug is that you cannot call file-write-date (and probably a bunch of other functions) on a "probe stream" (as obtained by calling open with :direction :probe). It raises an error, when it should at worst just return nil (see section 20.1.2 of the spec).
Someone at Franz replied to Mike by saying "I must say you are very good at finding somewhat obscure bugs in our filesystem interface." Heh. Somewhat obscure? I never thought of calling any functions on a closed stream, and the existence of :direction :probe was the biggest Lisp surprise I've had in about four years.