This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Reconciling Emacs Lisp and Scheme



Here are my notes (from long ago) on how to make Emacs Lisp and Scheme
cohabitate without too many feathers being ruffled.  Pat, could you
put this somewhere on the web site, and post its location to the list?



-----

Here's a plan for allowing Emacs Lisp and R4RS Scheme to share data
structures in Guile with pretty good transparency.

First, some background:

Guile will support both Emacs Lisp and Scheme, and allow code written
in one language to exchange values and share data structures with the
other.  Because Emacs Lisp and Scheme have very similar type systems,
this sharing can be almost transparent.

However, there are differences.  Emacs Lisp, following lisp tradition,
uses the symbol `nil' to represent the empty list and Boolean false.
On the other hand, Scheme has distinct objects for all three uses: the
symbol `nil' has no special significance, the empty list is written
'(), and the special object #f is false.  (It's the only false object,
in fact; all other objects are true in Scheme, including the empty
list.)

We would very much like to find an arrangement that allows all Emacs
Lisp code to run unchanged, allows all R4RS code to run unchanged, and
allows the two to communicate mostly transparently.

None of the obvious compromises work nicely.  Modifying either
language to match the other breaks existing code in ways that are
impossible to fix mechanically.  Making Emacs Lisp's nil identical to
either of Scheme's #f or '() will cause misinterpretations when Scheme
receives either Boolean values or lists from Emacs Lisp.

It's worth noting that this arises as a crucial issue only because
Emacs Lisp and Scheme values are so tantalizingly similar.  When
mixing languages with more blatantly different value worlds --- C and
Scheme, for example --- programmers should expect to be responsible
for making the necessary conversions.  But because the Scheme/Emacs
Lisp boundary is so transparent already, it's worthwhile to clear up
the few remaining discrepancies as much as possible.

In the following paragraphs, I'll try to avoid confusion by using this
notation:

I'll write #f for the value assigned by Scheme to the expression #f.
I'll write '() for the value assigned by Scheme to the expression '().
I'll write nil for the value assigned by Emacs Lisp to the expressions
	nil, '(), and ().

Guile will support Emacs Lisp by translating it into Scheme, and that
translation need not map Emacs Lisp forms onto their most obvious
Scheme counterparts; this gives us some room to maneuver.  For
example, Emacs Lisp's `if' form could be translated into a Scheme form
`lisp-if', which could handle Boolean values differently from the
normal Scheme `if'.

We want list-valued Scheme and Emacs Lisp functions to interoperate.
So Scheme must be able to return '() to Emacs Lisp, and have Emacs
Lisp recognize it as the empty list.  Emacs Lisp must be able to
return nil to Scheme, and have Scheme recognize it as the empty list.

We want Boolean-valued Scheme and Emacs Lisp functions to
interoperate.  So Scheme must be able to return #f to Emacs Lisp, and
have Emacs Lisp recognize it as false.  And Emacs Lisp must be able to
return nil to Scheme, and have Scheme recognize it as false.

Since it is standard in Emacs Lisp to test for the empty list with
`if' directly, Emacs Lisp must also recognize '() as false.

I don't see any harm in telling Emacs Lisp that #f is an empty list.
That merely equates two objects that Emacs Lisp never distinguished
anyway.

So, according to the above paragraphs:
- The Emacs Lisp end-of-list values are: nil, '(), #f
- The Emacs Lisp false values are: nil, '(), #f (same as above)
- The Scheme end-of-list values are: '(), nil
- The Scheme false values are: #f, nil

Because Emacs Lisp code frequently uses the `eq' function to examine
list structure, Emacs Lisp's `eq' should treat nil, '(), and #f as
identical.  Scheme's eq? must be able to distinguish the three.

When not mixing Scheme and Emacs Lisp, this preserves both languages
intact.  When mixing the two, this supports the interactions discussed
above.


Where does this screw up?

I'm told some people like to write Scheme functions that return either
a (possibly empty) list, or #f to indicate some sort of 'other' case.
If Emacs Lisp calls such a function, it won't be able to tell whether
it got an empty list or the 'other' case.  Here's another symptom of
the same clash: if Scheme places #f in the cdr of a pair, Scheme will
consider it an improper list, while Emacs Lisp will consider it a
proper list.

I don't see anything we can do to resolve this conflict, without
simply changing some of the user's code; such Scheme code simply
provides an unfortunate interface for Emacs Lisp callers.  We think
this is rare enough that it will suffice to tell programmers, "the
Emacs Lisp/Scheme boundary is almost transparent, but this is one
glitch you'll have to cope with."

Note that this approach does require Guile to distinguish between nil
and '(); this is necessary to allow Scheme callers to accept values
from Emacs Lisp Boolean-valued functions.


Can this be implemented efficiently?

I think so.  `eq' can use fast, approximate tests to cover most common
cases, and then fall back to a slower, correct function for the rest.
Something like this might be useful in the Emacs C code:

#define EQ(x, y) ((x) == (y) \
	          || ((((x) ^ (y)) & MASK) == 0) && lisp_eq ((x), (y)))

where MASK has very few zero bits, and the elements of the equivalence
classes have representations differing in only those bits.  The '=='
clause will catch most cases when EQ is true; the '^' clause will
catch most cases when EQ is false; and the lisp_eq function will be
always correct, but relatively slow.


I think this arrangement meets the needs of most of the Guile audience.
- Emacs Lisp programmers want their existing code to work when
  Emacs switches over to Guile.  They won't notice a thing.
- Some Scheme programmers want to use Guile as an ordinary Scheme
  interpreter, to take advantage of its debugging and systems
  programming features.  They won't notice a thing.
- Some Scheme programmers want to program Emacs in Scheme.
  There is no legacy of Scheme-for-Emacs code that we care about, so
  these people will deal with whatever we give them.
- Programmers writing new applications using Guile should be happy,
  too.  There is almost no extant Emacs Lisp code which doesn't use
  buffers and other Emacs-specific data types; any Emacs Lisp code
  they want to use in their application will need porting anyway.


Appendix: Why not just fix all the Emacs Lisp code?

Various people have asked why Emacs Lisp compatibility is so
important.  Some others have suggested adapting the Emacs Lisp code to
work with the Scheme boolean system.  I'd like to clarify why I don't
think that's practical.

One major reason the FSF is funding Guile work is that it plans to
replace Emacs's lisp interpreter with Guile.  Emacs 19.33 comes with
334,000 lines of lisp code; there is also a good amount we don't
distribute which is in widespread use anyway.  The assumption that the
empty list is false is ubiquitous in that code.  There is no reliable,
mechanical way to detect code which needs to be changed.  Even if
there were, such adaptations would often require changed interfaces,
so code far from the site of a nil/false test would also be affected.

In other words, by differentiating nil and false in Emacs Lisp, we
would create thousands of bugs spread throughout a third of a million
lines of source code, a good proportion of which will be non-trivial
to find and fix.

It seems clear that Scheme's semantics cannot be unified with Emacs
Lisp's semantics with perfect transparency.  I believe it can be done
with pretty good transparency.  However, Guile will *not*
differentiate the empty list and the false value in Emacs Lisp.

Subject: elisp needs to distinguish '() and #f, specially
From: thomas@gnu.ai.mit.edu (Thomas Bushnell, n/BSG)
To: jimb@red-bean.com
Subject: Re: Guile status report
Date: Tue, 10 Sep 1996 15:52:57 -0400
X-Name-Change: My name used to be `Michael'; now it is `Thomas'.
X-Tom-Swiftie: "I'm sorry I broke your window," Tom said painfully.


Suppose I write a scheme function that wants to distinguish returning
'() and #f.  

New Emacs lisp needs to be able to call such functions and know what's
going on.  I think the best way is to export Scheme's eq? to emacs as
something like `scheme-eq' so that cognizant Lisp programs can do the
right thing.

Thomas