Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Equality of foreign objects

8 views
Skip to first unread message

Alessio Stalla

unread,
Oct 14, 2009, 5:20:20 PM10/14/09
to
The hyperspec says of EQUAL that it behaves like EQ for every object
except in a bunch of special cases.
Does this mean that no conforming Common Lisp implementation can
extend EQUAL to meaningfully compare implementation-specific objects
(e.g., Java objects in ABCL or C values in C-based implementations,
etc)?
This sounds like a serious limitation to me; among other things, it
makes it impossible for such implementation-specific objects to be
treated as first-class Lisp objects - they cannot be seamlessly used
as keys in a hash-map, for example. Is there a reason for this, or was
it an overlook at the time the standard was written?

Alessio Stalla

Pascal J. Bourguignon

unread,
Oct 14, 2009, 6:11:33 PM10/14/09
to
Alessio Stalla <alessi...@gmail.com> writes:

> The hyperspec says of EQUAL that it behaves like EQ for every object
> except in a bunch of special cases.
> Does this mean that no conforming Common Lisp implementation can
> extend EQUAL to meaningfully compare implementation-specific objects
> (e.g., Java objects in ABCL or C values in C-based implementations,
> etc)?

AFAICS, yes.


> This sounds like a serious limitation to me;

Not at all. An implementation may provide SYSTEM:EQUAL-OBJECTS and
propose any behavior it wants there.


> among other things, it
> makes it impossible for such implementation-specific objects to be
> treated as first-class Lisp objects - they cannot be seamlessly used
> as keys in a hash-map, for example.

Again, not at all. An implementation may provide another constructor,
such as SYSTEM:MAKE-HASH-TABLE that would accept designators to other
test functions such as SYSTEM:EQUAL-OBJECTS.


> Is there a reason for this, or was
> it an overlook at the time the standard was written?

In my understanding, this kind of constraints were designed in to
allow efficient implementations.

--
__Pascal Bourguignon__

Pascal Costanza

unread,
Oct 14, 2009, 6:25:28 PM10/14/09
to

There is no generic equivalence predicate (in the CLOS sense) in Common
Lisp that can be extended for user-defined types, and there are good
reasons for that. Other languages that pretend to provide such generic
equivalence predicates get them wrong most of the time. The issues are
very subtle and very hard to solve. So it's better not to pretend that
you can solve them.

Just define your own custom equivalence predicates (like java-equals,
c-==, etc.) that do what you would expect from them. They are
straightforward to use in association lists and property lists, for
example. For hash-tables: Most Common Lisp implementations provide an
:sxhash option, or so, to provide your own function for determining a
hash code, and you can then pass your own custom hash function in a
similar way.


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

Don Geddis

unread,
Oct 14, 2009, 11:29:15 PM10/14/09
to
Alessio Stalla <alessi...@gmail.com> wrote on Wed, 14 Oct 2009:
> The hyperspec says of EQUAL that it behaves like EQ for every object except
> in a bunch of special cases. Does this mean that no conforming Common Lisp
> implementation can extend EQUAL to meaningfully compare
> implementation-specific objects (e.g., Java objects in ABCL or C values in
> C-based implementations, etc)?

Yes.

Kent Pitman has a reasonable discussion of these issues here:
http://www.nhplace.com/kent/PS/EQUAL.html

It is perhaps best to think of EQUAL, not as an incomplete function which
you might want to "extend", but instead as a complete function already
completely defined over all Lisp objects. One of many possible arbitrary
equality predicates you might want to define over all Lisp objects.

> This sounds like a serious limitation to me; among other things, it makes
> it impossible for such implementation-specific objects to be treated as
> first-class Lisp objects - they cannot be seamlessly used as keys in a
> hash-map, for example.

Implementations are not required to provide hash tables with arbitrary
equality functions. Only with a small specific set of completely-specified
equality functions.

But many implementations extend MAKE-HASH-TABLE to allow other tests.

> Is there a reason for this, or was it an overlook at the time the standard
> was written?

For MAKE-HASH-TABLE, it was probably efficiency. For EQUAL, Kent's paper
provides the bulk of the explanation: what you imagine you want probably
isn't semantically coherent.

-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org
I think a good joke to do at your wedding is, when you're supposed to say "I
do," instead say "I do NOW." (I'm not sure what it means, but maybe it'll get
a laugh.) -- Deep Thoughts, by Jack Handey [1999]

Lars Rune Nøstdal

unread,
Oct 15, 2009, 4:00:51 AM10/15/09
to
On Oct 14, 11:20 pm, Alessio Stalla <alessiosta...@gmail.com> wrote:
> The hyperspec says of EQUAL that it behaves like EQ for every object
> except in a bunch of special cases.
> Does this mean that no conforming Common Lisp implementation can
> extend EQUAL to meaningfully compare implementation-specific objects
> (e.g., Java objects in ABCL or C values in C-based implementations,
> etc)?
> This sounds like a serious limitation to me; among other things, it
> makes it impossible for such implementation-specific objects to be
> treated as first-class Lisp objects -

uh, why? .. just wrap the foreign singleton (so it has a unique
identity ref. EQ) test in a local test function (lambda (x) ..) and
"parse" the return value into something that makes sense on the lisp
end.

the same holds for other foreign resources like file descriptors .. if
i want the GC to handle those (finalization) i wrap them in a simple
(aka. cons, but struct if i want it to have a type) lisp object and do
the GC/finalization-->close thing on it "by proxy".

Michael Weber

unread,
Oct 15, 2009, 5:26:25 AM10/15/09
to
On Oct 14, 11:20 pm, Alessio Stalla <alessiosta...@gmail.com> wrote:

> This sounds like a serious limitation to me; among other things, it
> makes it impossible for such implementation-specific objects to be
> treated as first-class Lisp objects - they cannot be seamlessly used
> as keys in a hash-map, for example.

Alas, not all is lost. As other pointed out, you can write your own
wrappers with the desired functionality, and make them backwards
compatible with the CL versions. Then make up your own lisp dialect:

(defpackage #:stalla-lisp
(:nicknames #:sl)
(:use #:cl)
(:shadow ...)
(:export ...))

For an extensible equality and hash-table, have a look at:
http://www.foldr.org/~michaelw/projects/mw-equiv/
http://www.cliki.net/genhash

Lars Rune Nøstdal

unread,
Oct 15, 2009, 6:06:13 AM10/15/09
to
On Oct 15, 10:00 am, Lars Rune Nøstdal <larsnost...@gmail.com> wrote:
> On Oct 14, 11:20 pm, Alessio Stalla <alessiosta...@gmail.com> wrote:
>
> > The hyperspec says of EQUAL that it behaves like EQ for every object
> > except in a bunch of special cases.
> > Does this mean that no conforming Common Lisp implementation can
> > extend EQUAL to meaningfully compare implementation-specific objects
> > (e.g., Java objects in ABCL or C values in C-based implementations,
> > etc)?
> > This sounds like a serious limitation to me; among other things, it
> > makes it impossible for such implementation-specific objects to be
> > treated as first-class Lisp objects -
>
> uh, why? .. just wrap the foreign singleton (so it has a unique
> identity ref. EQ) test in a local test function (lambda (x) ..) and
> "parse" the return value into something that makes sense on the lisp
> end.

i'm not sure what i meant here .. *coffee* .. i think i might have
meant to wrap the foreign _value_ (not the "test"??), but what M.W.
mentions about shadowing of symbols might make more sense

if you wrap the value in a simple struct, you can augment the printer/
reader btw. .. so the foreign value can have some nice recognizable
visual representation in your REPL and in the Lisp debugger etc.

Alessio Stalla

unread,
Oct 15, 2009, 6:43:41 AM10/15/09
to

Thanks to everyone who answered. One point that perhaps wasn't clear
in my original post: I'm not talking about an user-extensible EQUAL
(although I think it would have been useful to provide a EQUIVALENT
generic function, even with the limitations pointed out by Kent Pitman
in his paper). I'm talking about the fact that CL implementations are
explicitly forbidden to provide an EQUAL that is more meaningful than
EQ for some implementation-specific objects, such as objects coming
from a foreign language but that the implementation has chosen to
treat as first-class entities. It's true that I, as a user, can work
around this limitation by a number of means; but EQUAL being the way
it is implies that user code must be targeted explicitly at a given
implementation to get equality right on that implementation.

E.g. imagine a generic memoization macro that uses an #'equal hash
table to memoize already-computed values: it will not work as one
would expect if the arguments for my memoized function were C strings,
or Java objects, or other "native" objects for which a "standard"
equality predicate exists, but it's not recognized by EQUAL and
everything that gravitates around it; objects which were otherwise
treated as first-class entities in my implementation.

I fail to see a valid reason for EQUAL being defined the way it is;
why couldn't the spec say something along the lines of
"implementations are permitted to give EQUAL a specialized meaning for
objects of types not defined in the CL standard, as long as (EQL x y)
implies (EQUAL x y) for any x, y"? Is it because the standard does not
contemplate other types of objects besides those it defines
explicitly? Or is there some other problem I fail to see?

Alessio

vippstar

unread,
Oct 15, 2009, 8:50:42 AM10/15/09
to
On Oct 15, 1:43 pm, Alessio Stalla <alessiosta...@gmail.com> wrote:
<snip>

> I fail to see a valid reason for EQUAL being defined the way it is;
> why couldn't the spec say something along the lines of
> "implementations are permitted to give EQUAL a specialized meaning for
> objects of types not defined in the CL standard, as long as (EQL x y)
> implies (EQUAL x y) for any x, y"? Is it because the standard does not
> contemplate other types of objects besides those it defines
> explicitly? Or is there some other problem I fail to see?

If you have an implementation in mind which would want to do that, it
can do it, but it can't claim CL conformance. It's not such a big
thing actually.

Pascal J. Bourguignon

unread,
Oct 15, 2009, 9:50:06 AM10/15/09
to
Alessio Stalla <alessi...@gmail.com> writes:
> I fail to see a valid reason for EQUAL being defined the way it is;

Basically, it is because what the definition defines is Common Lisp.
It cannot define EQUAL for non Common Lisp object, because if it did,
it wouldn't be defining Common Lisp anymore.


However, nothing prevents you to define a superset of Common Lisp.
That is a language that will behave and be defined exactly as Common
Lisp as long as you only use Common Lisp objects.

What happens when you use non-Common Lisp objects cannot be defined by
the Common Lisp definition, so I cannot say what would happen, but YOU
can define what would happen for non-Common Lisp objects. The problem
is that you cannot find this in the Common Lisp definition, since it
defines only Common Lisp, or else it wouldn't be the Common Lisp
definition.

--
__Pascal Bourguignon__

Alessio Stalla

unread,
Oct 15, 2009, 11:45:54 AM10/15/09
to
On Oct 15, 3:50 pm, p...@informatimago.com (Pascal J. Bourguignon)
wrote:

But the Common Lisp standard says that, for *any* object except the
few listed, EQUAL behaves like EQ. Thus it says that any superset of
CL cannot both extend EQUAL for other, non-CL objects, AND at the same
time remain an actual superset of CL. It says that a conforming CL
program can count on the fact that (equal x y) is the same as (eq x y)
except when x and y are numbers, strings or a few other kinds of
objects.
To my understanding, the CL standard does not limit CL extensions that
much in most other cases, and when it does, it does for serious
reasons. So either there is a serious reason in this case too, and I
don't understand it, or imho this aspect has been defined too
strictly.

...except if you interpret the phrase "Two other objects are equal
only if they are eq" as if it said "Two other *CL* objects are
equal..." meaning that EQUAL is undefined for non-CL objects (which of
course, being they non-CL, the standard cannot say anything about).

Alessio

Alessio Stalla

unread,
Oct 15, 2009, 11:48:34 AM10/15/09
to

Well in my opinion, it is actually a big thing. Most or all popular
extensions (such as gray streams, the exit/quit function, save-image,
weak references, ...) do not imply failure to comply to the CL
standard.

Pascal J. Bourguignon

unread,
Oct 15, 2009, 1:04:30 PM10/15/09
to
Alessio Stalla <alessi...@gmail.com> writes:

> On Oct 15, 3:50�pm, p...@informatimago.com (Pascal J. Bourguignon)
> wrote:
>> Alessio Stalla <alessiosta...@gmail.com> writes:
>> > I fail to see a valid reason for EQUAL being defined the way it is;
>>
>> Basically, it is because what the definition defines is Common Lisp.
>> It cannot define EQUAL for non Common Lisp object, because if it did,
>> it wouldn't be defining Common Lisp anymore.
>>
>> However, nothing prevents you to define a superset of Common Lisp.
>> That is a language that will behave and be defined exactly as Common
>> Lisp as long as you only use Common Lisp objects.
>>
>> What happens when you use non-Common Lisp objects cannot be defined by
>> the Common Lisp definition, so I cannot say what would happen, but YOU
>> can define what would happen for non-Common Lisp objects. �The problem
>> is that you cannot find this in the Common Lisp definition, since it
>> defines only Common Lisp, or else it wouldn't be the Common Lisp
>> definition.
>
> But the Common Lisp standard says that, for *any* object except the
> few listed, EQUAL behaves like EQ.

Of course, it cannot say otherwise!

> Thus it says that any superset of
> CL cannot both extend EQUAL for other, non-CL objects, AND at the same
> time remain an actual superset of CL.

No. It just cannot speak about any superset, by definition.
A superset language can define whatever it wants.

Notice how the catch all entry is defined:

Other (Structures, hash-tables, instances, ...)

Two other objects are equal only if they are eq.

equal does not descend any objects other than the ones explicitly
specified above. The next figure summarizes the information given
in the previous list. In addition, the figure specifies the
priority of the behavior of equal, with upper entries taking
priority over lower ones.

Since 'Other' and '...' would mean everything else, the expression
'any objects other than the ones explicitely specified above' means
either the empty set, or these 'Other' objects. In both cases, it is
non functional. Since 'Other' is defined in the parentheses as an
extension, it can refer only the Common Lisp objects that are known of
Common Lisp, not of any superset.


> [...]


> ...except if you interpret the phrase "Two other objects are equal
> only if they are eq" as if it said "Two other *CL* objects are
> equal..." meaning that EQUAL is undefined for non-CL objects (which of
> course, being they non-CL, the standard cannot say anything about).

Yes, this is how I interpret it.


--
__Pascal Bourguignon__

Alessio Stalla

unread,
Oct 15, 2009, 2:55:26 PM10/15/09
to
On Oct 15, 7:04 pm, p...@informatimago.com (Pascal J. Bourguignon)

Ok, now I understand. However, to me this interpretation seems very
counterintuitive, because if every time the hyperspec says 'object'
you read it as 'object of a type defined in the spec', then you can no
longer trust any single bit of the standard when you deal with
implementation-specific objects.
For example, the spec says of both arguments of CONS that they are 'an
object': does this mean that an implementation is allowed to have
(cons (threads:make-thread ...) (ffi:make-foreign-pointer ...)) return
42?
...worse! The type T represents 'The set of all objects': then
implementation-specific objects can (must?) not be of type T! I can't
really accept this view. I have always interpreted 'object' in the
loose sense of 'any first-class value', i.e. something which a
variable can be bound to, which can be passed as argument to a
function or returned from one, etc.

Alessio

Tamas K Papp

unread,
Oct 15, 2009, 3:11:40 PM10/15/09
to
On Thu, 15 Oct 2009 11:55:26 -0700, Alessio Stalla wrote:

> For example, the spec says of both arguments of CONS that they are 'an
> object': does this mean that an implementation is allowed to have (cons
> (threads:make-thread ...) (ffi:make-foreign-pointer ...)) return 42?
> ...worse! The type T represents 'The set of all objects': then
> implementation-specific objects can (must?) not be of type T! I can't
> really accept this view. I have always interpreted 'object' in the

I don't really understand how you arrived at this
analogy/interpretation. I would argue the contrary: as equal is
defined for all objects (regardless of whether they are
implementation-specific), so is cons. I see no problem here.

Also, I don't really see how these things limit you in practice. CL
is flexible enough so that you can build your version of equal and
hash-tables easily, and even make them pretty fast if needed. The
standard had to draw the line somewhere. Sometimes I also grumble
about some things (eg no CLOS dispatch on array-element-type, etc),
but hey, I can work around these things easily. I don't really expect
the authors of the CLHS to anticipate everything I need, especially as
the latter is a moving target.

Tamas

Pascal J. Bourguignon

unread,
Oct 15, 2009, 3:14:17 PM10/15/09
to
Alessio Stalla <alessi...@gmail.com> writes:

That's the point of implementation specific extensions: they are
implementation specific.

For example, we could write: (cons a nil), and if A is bound to a
delay object, then (1+ (car (cons a nil))) would not be the same thing
as is bound to A.

(let ((a (system:delay (* 2 24))))
(print (system:evaluatedp a)) ; would print NIL
(print (car (cons a nil))) ; could print #<FUTURE (* 2 24)>
(print (CL:1+ (car (cons a nil)))) ; would print 43
(print (system:evaluatedp a)) ; would print T
(print (car (cons a nil))) ; would print 42
(values))

It really would depend on the implementation, and how it would extend
CL operations to force the delayed expressions.

--
__Pascal Bourguignon__

Alessio Stalla

unread,
Oct 15, 2009, 3:30:33 PM10/15/09
to
On Oct 15, 9:11 pm, Tamas K Papp <tkp...@gmail.com> wrote:
> On Thu, 15 Oct 2009 11:55:26 -0700, Alessio Stalla wrote:
> > For example, the spec says of both arguments of CONS that they are 'an
> > object': does this mean that an implementation is allowed to have (cons
> > (threads:make-thread ...) (ffi:make-foreign-pointer ...)) return 42?
> > ...worse! The type T represents 'The set of all objects': then
> > implementation-specific objects can (must?) not be of type T! I can't
> > really accept this view. I have always interpreted 'object' in the
>
> I don't really understand how you arrived at this
> analogy/interpretation.  I would argue the contrary: as equal is
> defined for all objects (regardless of whether they are
> implementation-specific), so is cons.  I see no problem here.

Pascal - as I have understood - interprets things very differently,
i.e. that equal is NOT defined for all objects, but only for those
kinds of objects explicitly mentioned in the CL standard.

> Also, I don't really see how these things limit you in practice.  CL
> is flexible enough so that you can build your version of equal and
> hash-tables easily, and even make them pretty fast if needed.  The
> standard had to draw the line somewhere.  Sometimes I also grumble
> about some things (eg no CLOS dispatch on array-element-type, etc),
> but hey, I can work around these things easily.  I don't really expect
> the authors of the CLHS to anticipate everything I need, especially as
> the latter is a moving target.

Under your interpretation, *I* (the user) can do as you say, but *the
implementation* can not adapt EQUAL, MAKE-HASH-TABLE and other CL
functions to its own objects without breaking adherence to the
standard - even if, as both you and Pascal say (and I agree), the
standard says nothing about such other kinds of objects. This does not
limit me as a user, but (imho) needlessly limit me as an implementor.

Alessio Stalla

unread,
Oct 15, 2009, 3:33:37 PM10/15/09
to
On Oct 15, 9:14 pm, p...@informatimago.com (Pascal J. Bourguignon)
wrote:

Ok - then do you agree that

(let ((a (system:delay (* 2 21)))) ;I suppose you meant 21, not 24
(CL:equal a 42))

could return T without breaking compatibility with the standard?

A.

Pascal J. Bourguignon

unread,
Oct 15, 2009, 4:21:21 PM10/15/09
to
Alessio Stalla <alessi...@gmail.com> writes:

Yes. Since the standard doesn't consider delayed expressions, the
evaluation rules concerning delayed experssions are out of scope. You
cannot use the CL standard to know what the above expressions means.
So the superset language would have to define how (CL:equal a 42) is
evaluated, and whether it will be true or nil. It could define it to
be true.

--
__Pascal Bourguignon__

Tim Bradshaw

unread,
Oct 15, 2009, 4:27:40 PM10/15/09
to
On 2009-10-14 22:20:20 +0100, Alessio Stalla <alessi...@gmail.com> said:

> Does this mean that no conforming Common Lisp implementation can
> extend EQUAL to meaningfully compare implementation-specific objects
> (e.g., Java objects in ABCL or C values in C-based implementations,
> etc)?

I'm not sure whether such an implementation would be conforming or not.
I think it would be a poor implementation however. As others have
suggested, you should read Kent Pitman's paper on equality: it is a
much, much more subtle concept than you probably think it is.

> This sounds like a serious limitation to me; among other things, it
> makes it impossible for such implementation-specific objects to be
> treated as first-class Lisp objects - they cannot be seamlessly used
> as keys in a hash-map, for example. Is there a reason for this, or was
> it an overlook at the time the standard was written?

This is not the case. An implementation could quite happily provide
its own extensions which allow this.

Alessio Stalla

unread,
Oct 15, 2009, 4:36:29 PM10/15/09
to
On Oct 15, 10:21 pm, p...@informatimago.com (Pascal J. Bourguignon)
wrote:

So it could also define (equal (java:jnew "java.lang.String")
(java:jnew "java.lang.String")) to be T.
Or (equal (ffi:make-foreign-array :int 3 :initial-element 0) (ffi:make-
foreign-array :int 3 :initial-element 0)) to be T. And so on.

This is the opposite of what you originally said (and what I
interpreted in the spec):

me: "The hyperspec says of EQUAL that it behaves like EQ for every


object except in a bunch of special cases. Does this mean that no
conforming Common Lisp implementation can extend EQUAL to meaningfully
compare implementation-specific objects (e.g., Java objects in ABCL or
C values in C-based implementations, etc)?"

you: "AFAICS, yes."

What do other people think?

A.

Tamas K Papp

unread,
Oct 15, 2009, 4:46:03 PM10/15/09
to
On Thu, 15 Oct 2009 12:30:33 -0700, Alessio Stalla wrote:

> On Oct 15, 9:11 pm, Tamas K Papp <tkp...@gmail.com> wrote:
>> Also, I don't really see how these things limit you in practice.  CL is
>> flexible enough so that you can build your version of equal and
>> hash-tables easily, and even make them pretty fast if needed.  The
>> standard had to draw the line somewhere.  Sometimes I also grumble
>> about some things (eg no CLOS dispatch on array-element-type, etc), but
>> hey, I can work around these things easily.  I don't really expect the
>> authors of the CLHS to anticipate everything I need, especially as the
>> latter is a moving target.
>
> Under your interpretation, *I* (the user) can do as you say, but *the
> implementation* can not adapt EQUAL, MAKE-HASH-TABLE and other CL
> functions to its own objects without breaking adherence to the standard

Perhaps I was unclear. I meant that you can implement these things,
and call them something else (eg equal*). Or even (for hash tables)
use the implementation's extended features, and then implement a
trivial-super-general-hash-tables library as a thin, unified API. I
didn't mean to suggest that either the user or "the implementation"
adapt equal etc, I think it is much cleaner to start anew if you want
to do something different.

> - even if, as both you and Pascal say (and I agree), the standard says
> nothing about such other kinds of objects. This does not limit me as a
> user, but (imho) needlessly limit me as an implementor.

Frankly, especially with open source implementations, I find the line
between implementor and user quite blurry. But anyhow, even the
implementor can do this things, it is just that his implementation
won't be conforming. Big deal. Or she can add a switch that enforces
the CL standard on demand, like C compiler switches.

In any case, I don't find your original issue to be a source of
significant practical difficulty. Maybe it would be neater for you in
this case if you could "extend" equal, but I imagine how it would
break or make impractical many things (optimizations, etc) and I am
OK with the choice made by the writers of the standard.

Best,

Tamas

Pascal J. Bourguignon

unread,
Oct 15, 2009, 4:52:48 PM10/15/09
to
Alessio Stalla <alessi...@gmail.com> writes:

We're talking of two different things.

Either we consider a Common Lisp implementation, and therefore
java:jnew should return a Common Lisp object, and therefore the
specification of CL:EQUAL applies,

or we consider a new language, possibly a superset of CL, where
java:jnew returns something else, and for which the specification of
CL:EQUAL doesn't applies, but the extension of CL:EQUAL in the
superset does something that just cannot be specified by Common Lisp,
but that must be specified by the superset language, and that can be
whatever you, as the specifier, want it to be.


--
__Pascal Bourguignon__

Alessio Stalla

unread,
Oct 15, 2009, 5:02:36 PM10/15/09
to
On Oct 15, 10:27 pm, Tim Bradshaw <t...@cley.com> wrote:

> On 2009-10-14 22:20:20 +0100, Alessio Stalla <alessiosta...@gmail.com> said:
>
> > Does this mean that no conforming Common Lisp implementation can
> > extend EQUAL to meaningfully compare implementation-specific objects
> > (e.g., Java objects in ABCL or C values in C-based implementations,
> > etc)?
>
> I'm not sure whether such an implementation would be conforming or not.

Me neither, that's why I posted ;)

>  I think it would be a poor implementation however.  As others have
> suggested, you should read Kent Pitman's paper on equality: it is a
> much, much more subtle concept than you probably think it is.

I have read Kent's paper, and found it quite enlightening. If I have
understood it correctly, it basically says that there's no such thing
as The Right Equality Function, but rather that equality is not a very
well-defined concept and could be implemented with various semantics;
and that EQUAL and the like are not "more right" than other possible
equality predicates, they are defined more following a widely accepted
tradition than anything else.

However, I'm not attempting to define the one definitive equal. I'm
just saying that - imho - an implementation could provide, for
convenience, a default (and arbitrary!) implementation of the EQUAL
function which does not behave like EQ for certain kinds of
implementation-specific objects. Such an EQUAL would be not "more
right" than other possible implementations, just maybe more convenient
in those cases that happen to be common in that implementation (but
then, convenience depends on what the user wants).
If the hyperspec prohibits an implementation to provide such an EQUAL,
I think this is a needless limitation, and no one has managed to
convince me of the opposite.

Tamas K Papp

unread,
Oct 15, 2009, 5:17:35 PM10/15/09
to
On Thu, 15 Oct 2009 14:02:36 -0700, Alessio Stalla wrote:

> However, I'm not attempting to define the one definitive equal. I'm just
> saying that - imho - an implementation could provide, for convenience, a
> default (and arbitrary!) implementation of the EQUAL function which does
> not behave like EQ for certain kinds of implementation-specific objects.
> Such an EQUAL would be not "more right" than other possible
> implementations, just maybe more convenient in those cases that happen
> to be common in that implementation (but then, convenience depends on
> what the user wants). If the hyperspec prohibits an implementation to
> provide such an EQUAL, I think this is a needless limitation, and no one
> has managed to convince me of the opposite.

How is this a limitation? What prevents _you_ from defining this
clever function, calling it something else, and programming happily
ever after?

Tamas

Alessio Stalla

unread,
Oct 15, 2009, 5:46:18 PM10/15/09
to

If _I_ define this function, only I can use it. If the implementation
provides an EQUAL which works exactly like the EQUAL defined by the CL
standard, but that is not like EQ for some set of implementation-
specific objects (about which the standard says nothing), any code
that was written generically for CL will benefit of the implementation-
specific EQUAL, without knowing anything about my implementation. This
is (seems to be) allowed for most other functions: PRINT will print
anything, not just standard CL objects; the standard doesn't say, "for
any other object X, (PRINT X) prints #<object>", and if it did, I
believe it would be an unnecessary limitation. I fail to understand
why EQUAL must be different in this respect, yet the wording in the
spec seems to suggest it is, unless you interpret it as Pascal wrote,
but that has its own host of problems in my opinion.

A.

Alessio Stalla

unread,
Oct 15, 2009, 5:49:27 PM10/15/09
to
On Oct 15, 10:52 pm, p...@informatimago.com (Pascal J. Bourguignon)

Ok - sorry for being so stubborn. That's perfectly clear. The point
is: would that hypothetical superset of CL be a real superset (i.e. be
a conforming implementation of the CL standard), or not?

Scott Burson

unread,
Oct 15, 2009, 7:04:39 PM10/15/09
to
On Oct 14, 3:25 pm, Pascal Costanza <p...@p-cos.net> wrote:
>
> There is no generic equivalence predicate (in the CLOS sense) in Common
> Lisp that can be extended for user-defined types, and there are good
> reasons for that. Other languages that pretend to provide such generic
> equivalence predicates get them wrong most of the time. The issues are
> very subtle and very hard to solve.

No, they're really not. The correct rule is very simple: for
(mutable) object types, equality is identity; for (immutable) value
types, equality is by type-and-content (e.g. two sequence values are
equal iff they are of the same size and their elements are pairwise
equal). The little-known language Refine, which I used for years,
does things this way and it works great.

The problem is, most languages (like CL) treat all aggregates (by
which I mean both structures and collections) as objects; they don't
have a notion of tuples ("structure values", if you will) or
collection values. This is why I wrote FSet :)

FSet has a single, extensible equality predicate, EQUAL?. It follows
the above rule to the extent that is possible in CL. Alas, it isn't
always possible: on lists, strings, and (nonstring) vectors, there
really was nothing I could do but compare by type-and-content.
Technically, this is wrong because these are mutable, object types,
but on the other hand it is also convenient because they (particularly
lists and strings) are frequently used functionally, in that they are
never modified after construction.

> Just define your own custom equivalence predicates (like java-equals,
> c-==, etc.) that do what you would expect from them. They are
> straightforward to use in association lists and property lists, for
> example. For hash-tables: Most Common Lisp implementations provide an
> :sxhash option, or so, to provide your own function for determining a
> hash code, and you can then pass your own custom hash function in a
> similar way.

Or... use FSet :) I think you will find it more convenient to extend
EQUAL? to cover your own types.

-- Scott

Don Geddis

unread,
Oct 15, 2009, 7:00:32 PM10/15/09
to
Alessio Stalla <alessi...@gmail.com> wrote on Thu, 15 Oct 2009:
> If the implementation provides an EQUAL which works exactly like the EQUAL
> defined by the CL standard, but that is not like EQ for some set of
> implementation- specific objects (about which the standard says nothing),
> any code that was written generically for CL will benefit of the
> implementation- specific EQUAL, without knowing anything about my
> implementation.

I think you've explained this well enough.

> This is (seems to be) allowed for most other functions: PRINT will print
> anything, not just standard CL objects; the standard doesn't say, "for any
> other object X, (PRINT X) prints #<object>", and if it did, I believe it
> would be an unnecessary limitation.

I agree with you. You could imagine that the CL spec defined yet another
equality operation, EQUIVALENT, which was much like PRINT (as you say):
that it has some default behavior, but it could be customized for specific
types by user code, and any existing function which already used EQUIVALENT
would then immediately change behavior when presented with the specific
data types.

> I fail to understand why EQUAL must be different in this respect, yet the
> wording in the spec seems to suggest it is

I think the answer is supposed to be: fixing EQUAL allows those functions
(like MAKE-HASH-TABLE) which use it, to be implemented more efficiently.
An implementation doesn't need to allow for a possibly generic function call
in the middle of a tight loop during those tests. Instead, the test can be
inlined.

But I'm not an implementor, so I don't know for sure what the exact tradeoffs
are here.

-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org

Sometimes I think the world has gone completely mad. And then I think, "Aw,
who cares?" And then I think, "Hey, what's for supper?"

Pascal J. Bourguignon

unread,
Oct 15, 2009, 7:21:58 PM10/15/09
to
Alessio Stalla <alessi...@gmail.com> writes:

AFAIK, yes. You must consider CL as a subset, that is, you will
consider only the things that are defined in Common Lisp, when you're
checking whether that subset is CL or not.

Mathematically, the superset defines a function equal:

equal : SO x SO --> SO
(a , b) |-> true* or NIL

SO being the set of the Superset language Objects, and true* ∈ SO-{NIL}

If CO is the set of Common Lisp Objects, with CO ⊂ SO, then all that
is required is that the restriction of equal to CO, equal/CO to match
the specifications given by the Common Lisp standard of EQUAL.

equal/CO : CO x CO --> CO
(a , b) |-> true or NIL

with true ∈ CO-{NIL}.

Now, clearly, for any element a or b in SO-C0, equal(a,b) may be
defined as you want, but it's independent from the fact that equal/CO
matches the definition of Common Lisp, that is, that CL is a subset of
that super language.


Again, it's up to the designer of the superset language to make it a
"real superset", that is to arrange that the restriction to Common
Lisp is conformant to Common Lisp.


--
__Pascal Bourguignon__

D Herring

unread,
Oct 15, 2009, 11:24:19 PM10/15/09
to
Scott Burson wrote:
> On Oct 14, 3:25 pm, Pascal Costanza <p...@p-cos.net> wrote:
>> There is no generic equivalence predicate (in the CLOS sense) in Common
>> Lisp that can be extended for user-defined types, and there are good
>> reasons for that. Other languages that pretend to provide such generic
>> equivalence predicates get them wrong most of the time. The issues are
>> very subtle and very hard to solve.
>
> No, they're really not. The correct rule is very simple: for
> (mutable) object types, equality is identity; for (immutable) value
> types, equality is by type-and-content (e.g. two sequence values are
> equal iff they are of the same size and their elements are pairwise
> equal). The little-known language Refine, which I used for years,
> does things this way and it works great.

On the other hand, equality is not an intrinsic property; it requires
a well-defined metric. The number 1 is not equal to the number 5,
except modulo 2 or 4, or ...

Your rule is a good one, but it is just one rule more equal than others.

- Daniel

Scott Burson

unread,
Oct 16, 2009, 1:49:49 AM10/16/09
to

I think it's more than that. Equality is supposed to be the finest
possible equivalence relation. The fact that there exist coarser
equivalence relations that might be of use to someone is irrelevant.

This is why it really is wrong to compare (mutable) objects by type-
and-content, despite that lots of languages do it, and even FSet is
forced to go along in some common cases. It is always possible to
tell two mutable objects apart, if they really are distinct, by
modifying one and seeing that the other isn't affected. So type-and-
content comparison can never provide the finest possible equivalence
relation.

-- Scott

Pascal Costanza

unread,
Oct 16, 2009, 3:06:15 AM10/16/09
to
Scott Burson wrote:
> On Oct 14, 3:25 pm, Pascal Costanza <p...@p-cos.net> wrote:
>> There is no generic equivalence predicate (in the CLOS sense) in Common
>> Lisp that can be extended for user-defined types, and there are good
>> reasons for that. Other languages that pretend to provide such generic
>> equivalence predicates get them wrong most of the time. The issues are
>> very subtle and very hard to solve.
>
> No, they're really not. The correct rule is very simple: for
> (mutable) object types, equality is identity; for (immutable) value
> types, equality is by type-and-content (e.g. two sequence values are
> equal iff they are of the same size and their elements are pairwise
> equal). The little-known language Refine, which I used for years,
> does things this way and it works great.

...but is too simple in the general case. Consider very simple examples
like caches, which are just one case of properties that you may want to
exclude from being taken into account.

Then there is the notion of structural equivalence which you may not
cover by your definition.

See http://users.encs.concordia.ca/~grogono/Writings/CopyCompare.pdf for
a very well written paper on this subject.


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

Tamas K Papp

unread,
Oct 16, 2009, 3:37:08 AM10/16/09
to
On Thu, 15 Oct 2009 14:46:18 -0700, Alessio Stalla wrote:

> On Oct 15, 11:17 pm, Tamas K Papp <tkp...@gmail.com> wrote:
>> On Thu, 15 Oct 2009 14:02:36 -0700, Alessio Stalla wrote:
>> > However, I'm not attempting to define the one definitive equal. I'm
>> > just saying that - imho - an implementation could provide, for
>> > convenience, a default (and arbitrary!) implementation of the EQUAL
>> > function which does not behave like EQ for certain kinds of
>> > implementation-specific objects. Such an EQUAL would be not "more
>> > right" than other possible implementations, just maybe more
>> > convenient in those cases that happen to be common in that
>> > implementation (but then, convenience depends on what the user
>> > wants). If the hyperspec prohibits an implementation to provide such
>> > an EQUAL, I think this is a needless limitation, and no one has
>> > managed to convince me of the opposite.
>>
>> How is this a limitation?  What prevents _you_ from defining this
>> clever function, calling it something else, and programming happily
>> ever after?
>
> If _I_ define this function, only I can use it. If the implementation

I don't really see why: if you make the source available, anyone can
use it.

I guess what you mean is that you would like it to be integrated into
the rest of the CL library. With functions that take a :test argument
you are going to be fine. With some parts of the library like hash
tables, you will have to roll your own, but I don't think that this is
a huge issue.

> provides an EQUAL which works exactly like the EQUAL defined by the CL
> standard, but that is not like EQ for some set of implementation-
> specific objects (about which the standard says nothing), any code that
> was written generically for CL will benefit of the implementation-
> specific EQUAL, without knowing anything about my implementation. This

So provide an equal* as a generic function, implement it for some
objects, polish it up as a library, and voila. If there is demand for
what you are talking about, it will be used.

Sorry, but I still fail to see how the lack of extensibility for equal
would be limiting you in any practical way.

Tamas

Alessio Stalla

unread,
Oct 16, 2009, 4:00:26 AM10/16/09
to

Yes, and so? If two mutable objects are "equal" at a certain time,
being them mutable you don't have the guarantee that they'll stay
"equal" all the time, just like if you print a structure at two
different times you don't have the guarantee that the same string will
be printed. How is this wrong? This is the very nature of mutability.

> So type-and-content comparison can never provide the finest possible equivalence
> relation.
>
> -- Scott

Alessio Stalla

unread,
Oct 16, 2009, 4:58:44 AM10/16/09
to

Because I'm talking about extensibility by the implementor, not by me
(the user)! The user can always do anything he want, he can design his
own language or extensions, and use those and be happy. A CL
implementation does not have the freedom to invent its own language,
or it cannot be called a CL anymore. The CL standard must limit
implementations in a lot of ways to clearly define what CL is and what
it is not. However, to limit EQUAL so that no superset of CL can adapt
it to its own objects (if you read the spec as saying that, which
Pascal doesn't, and he's convinced me, too) is, imho, a needlessly
strict limitation.

Alessio

Raffael Cavallaro

unread,
Oct 16, 2009, 10:06:58 PM10/16/09
to
On 2009-10-16 04:58:44 -0400, Alessio Stalla <alessi...@gmail.com> said:

> Because I'm talking about extensibility by the implementor, not by me
> (the user)! The user can always do anything he want, he can design his
> own language or extensions, and use those and be happy. A CL
> implementation does not have the freedom to invent its own language,
> or it cannot be called a CL anymore.

An implementation has exactly the same freedom as a user as long as
extensions are added as extensions, and are not misrepresented as the
standard language.

abcl could implement an equal* generic function which is defined for
certain types, including, for example, java objects, and which users
could extend. abcl just shouldn't redefine common-lisp:equal in ways
that are incompatible with the standard.
--
Raffael Cavallaro

Keith H Duggar

unread,
Oct 16, 2009, 10:54:58 PM10/16/09
to
On Oct 16, 3:06 am, Pascal Costanza <p...@p-cos.net> wrote:
> Scott Burson wrote:
> > On Oct 14, 3:25 pm, Pascal Costanza <p...@p-cos.net> wrote:
> >> There is no generic equivalence predicate (in the CLOS sense) in Common
> >> Lisp that can be extended for user-defined types, and there are good
> >> reasons for that. Other languages that pretend to provide such generic
> >> equivalence predicates get them wrong most of the time. The issues are
> >> very subtle and very hard to solve.
>
> > No, they're really not. The correct rule is very simple: for
> > (mutable) object types, equality is identity; for (immutable) value
> > types, equality is by type-and-content (e.g. two sequence values are
> > equal iff they are of the same size and their elements are pairwise
> > equal). The little-known language Refine, which I used for years,
> > does things this way and it works great.
>
> ...but is too simple in the general case. Consider very simple examples
> like caches, which are just one case of properties that you may want to
> exclude from being taken into account.
>
> Then there is the notion of structural equivalence which you may not
> cover by your definition.
>
> Seehttp://users.encs.concordia.ca/~grogono/Writings/CopyCompare.pdffor
> a very well written paper on this subject.

"very well written"? Really?? Personally I would call it a
mediocre cacophony of rediscovered old ideas. Perhaps that
is why it never it out of proceedings and into a journal.

KHD

Scott Burson

unread,
Oct 17, 2009, 12:53:36 AM10/17/09
to
On Oct 16, 12:06 am, Pascal Costanza <p...@p-cos.net> wrote:
> Scott Burson wrote:
> > On Oct 14, 3:25 pm, Pascal Costanza <p...@p-cos.net> wrote:
> >> There is no generic equivalence predicate (in the CLOS sense) in Common
> >> Lisp that can be extended for user-defined types, and there are good
> >> reasons for that. Other languages that pretend to provide such generic
> >> equivalence predicates get them wrong most of the time. The issues are
> >> very subtle and very hard to solve.
>
> > No, they're really not.  The correct rule is very simple: for
> > (mutable) object types, equality is identity; for (immutable) value
> > types, equality is by type-and-content (e.g. two sequence values are
> > equal iff they are of the same size and their elements are pairwise
> > equal).  The little-known language Refine, which I used for years,
> > does things this way and it works great.
>
> ...but is too simple in the general case. Consider very simple examples
> like caches, which are just one case of properties that you may want to
> exclude from being taken into account.

Yes, there are times when, for efficiency, a class implementing a
value type may wish to cache certain information, which means both
that instances of the class are internally mutated and, as you say,
that that cache is not part of the value the instance represents.

I do not actually think this is an exception to the rule I gave. I
didn't say that type-and-content comparisons must necessarily use all
the slots of the instance. In order for a cache to be legitimate, in
the situation we are contemplating, the state of the cache must make
no difference to the semantics of the operations of the class -- only
to their performance. It would therefore not be unreasonable to
suggest that it is not part of the "content" of the object.

> Then there is the notion of structural equivalence which you may not
> cover by your definition.
>
> See http://users.encs.concordia.ca/~grogono/Writings/CopyCompare.pdf for
> a very well written paper on this subject.

You refer me to this paper as if you think it contains an argument
that supports your position. In fact I've said some of the same
things the authors do -- starting with the emphasis on the object/
value distinction; also see the first full paragraph on p. 10. More
to the point, I don't see anything in the paper that supports the view
you express thus:

> The issues are very subtle and very hard to solve. So it's better not
> to pretend that you can solve them.

Quite the contrary: the authors seem to feel they understand the
solution. I don't know that I agree with every detail -- I haven't
fully studied the paper -- but broadly, I think they're on the right
track.

-- Scott

Scott Burson

unread,
Oct 17, 2009, 1:17:31 AM10/17/09
to

Once again you have introduced a coarser equivalence relation than
equality. Certainly you should use whatever equivalence relations are
appropriate in your code; I am just saying these are not equality, and
you shouldn't call them equality.

Here's one reason why. There are lots of collection data structures
that require an immutable definition of equality. Suppose I put a
mutable object in a hashtable using an equivalence relation (and
therefore also a hash function) defined in the way you suggest. If I
then modify the object, I will have broken a key invariant of the
table: there will be an object in the table in a bucket not addressed
by its hash value (since that hash value will, in general, have
changed).

Again, programs use various equivalence relations for various
purposes. I'm not saying they shouldn't do so; I'm just saying they
shouldn't confuse them with equality. In particular, they shouldn't
_call_ them "equals" (however that is spelled in the language in use).

So CL:EQUAL, in my opinion, would better have been called something
like SXEQUAL, to go with SXHASH. (You see, it's not necessarily a
large change I'm recommending; merely adding a qualifier to the word
"equal" can suffice.) As for EQUALP, well, my inclination would be to
dump it; I don't think I've ever used it. I can't think of a good
name for it, and that, to me, is a great argument for getting rid of
something.

-- Scott

Raffael Cavallaro

unread,
Oct 17, 2009, 1:44:58 AM10/17/09
to
On 2009-10-17 00:53:36 -0400, Scott Burson <fset...@gmail.com> said:

> Quite the contrary: the authors seem to feel they understand the
> solution.

Yes, but the "solution" is for the language implementor not to pretend
that there is one true comparison/copy semantics:

"The language should not provide separate public methods for shallow
and deep copying and comparison, but only one copy method and one
comparison method for each class. The designer of the class, rather
than its clients, should choose appropriate semantics for these
methods."

(i.e., the class's programmer *not* the language designer and *not* the
client determines the semantics of "equal" and "copy.")

and:

"The copy procedure shallow-copies each essential attribute of the
source ob- ject, unless the programmer has indicated that an attribute
should be deep- copied."

i.e., the default equality should be shallow comparison, but
programmers can and should override this default depending on the
semantics of their application.

IOW, determination of object equality is entirely dependent on the
intended program semantics. You feel that there is one obviously
correct semantics which is a functional one - if objects are mutable,
equality is identity, if immutable, equality is recursive comparison.
But other programmers will want different semantics, so there is no
one-size-fits-all. To put it another way "it works great" translates to
"it works great *for me*" but others may not find that it works as they
want.

Finally I'll note that the semantics you favor are similar to (the same
as?) Baker's Egal, which is the explicit model Rich Hickey used for
Clojure's notion of equality.
--
Raffael Cavallaro

Alessio Stalla

unread,
Oct 17, 2009, 5:14:57 AM10/17/09
to
On Oct 17, 4:06 am, Raffael Cavallaro
<raffaelcavall...@pas.espam.s.il.vous.plait.mac.com> wrote:

> On 2009-10-16 04:58:44 -0400, Alessio Stalla <alessiosta...@gmail.com> said:
>
> > Because I'm talking about extensibility by the implementor, not by me
> > (the user)! The user can always do anything he want, he can design his
> > own language or extensions, and use those and be happy. A CL
> > implementation does not have the freedom to invent its own language,
> > or it cannot be called a CL anymore.
>
> An implementation has exactly the same freedom as a user as long as
> extensions are added as extensions, and are not misrepresented as the
> standard language.

I agree.

> abcl could implement an equal* generic function which is defined for
> certain types, including, for example, java objects, and which users
> could extend.

Again, it would not be the same thing. What you propose could well be
a portable equality library, maybe with built-in implementation-
specific extensions. What I propose can not be a library, it can only
be done by an implementation, since it affects the behavior of a
standard CL function.

> abcl just shouldn't redefine common-lisp:equal in ways
> that are incompatible with the standard.

Sure, I'm not saying otherwise! What I wanted to understand is whether
"redefining" cl:equal *only for objects not defined by the CL
standard* is or is not an incompatibility with the standard. Pascal J.
Bourguignon has made a convincing argument of the fact that it is not
an incompatibility. I have still not heard an argument for the
stricter interpretation of the standard (equal = eq for any possible
object, defined by the spec or not, except the few exceptions listed
by the spec).

Alessio

Tim Bradshaw

unread,
Oct 17, 2009, 6:54:15 AM10/17/09
to
On 2009-10-17 06:17:31 +0100, Scott Burson <fset...@gmail.com> said:

> So CL:EQUAL, in my opinion, would better have been called something
> like SXEQUAL, to go with SXHASH. (You see, it's not necessarily a
> large change I'm recommending; merely adding a qualifier to the word
> "equal" can suffice.) As for EQUALP, well, my inclination would be to
> dump it; I don't think I've ever used it. I can't think of a good
> name for it, and that, to me, is a great argument for getting rid of
> something.

Both of these proposals depend on there not having been a body of code
which CL was trying not to break.

Tim Bradshaw

unread,
Oct 17, 2009, 7:10:08 AM10/17/09
to
On 2009-10-17 10:14:57 +0100, Alessio Stalla <alessi...@gmail.com> said:

> Sure, I'm not saying otherwise! What I wanted to understand is whether
> "redefining" cl:equal *only for objects not defined by the CL
> standard* is or is not an incompatibility with the standard. Pascal J.
> Bourguignon has made a convincing argument of the fact that it is not
> an incompatibility. I have still not heard an argument for the
> stricter interpretation of the standard (equal = eq for any possible
> object, defined by the spec or not, except the few exceptions listed
> by the spec).

As I think I said, I'm not sure whether it is compatible or not. I
think it is clear that such an implementation would be a very poor
implementation as it would be very hard to write code in it which did
not do surprising things.

For instance, imagine something like this:

(typecase x
((or number character)
... code which knows EQUAL is equivalent to EQL ...)
(cons
... code which understands how EQUAL behaves on conses ...)
((or string bit-vector)
... how EQUAL behaves on these ...)
(pathname
... how EQUAL behaves on these ...)
(t
;; OK, we can assume that EQUAL is EQ here
...))

(I may not have got all the special cases here, but my intent is clear
I think). In an implementation which defines, or may define EQUAL as
other than EQ for non-CL-defined classes, this code will be wrong, and
it would not be possible to fix it other than in an
implementation-dependent way. That's just horrible.

Instead, if an implementation wants an extensible notion of
equivalence, it should define one.

Pascal J. Bourguignon

unread,
Oct 17, 2009, 8:18:59 AM10/17/09
to
Tim Bradshaw <t...@cley.com> writes:

Indeed. But my point is that in a conformant program, X wouldn't be
of an extension type. X here would only be of a standard Common Lisp
type, therefore in the T branch, EQUAL indeed would behave like EQ for
the remaining Common Lisp types.


Alternatively, a conformant program could be written adding a clause:

#+with-strange-type
(strange-type
;; here EQUAL behaves like EQUAL*
)


> Instead, if an implementation wants an extensible notion of
> equivalence, it should define one.

--
__Pascal Bourguignon__

Tim Bradshaw

unread,
Oct 17, 2009, 9:16:16 AM10/17/09
to
On 2009-10-17 13:18:59 +0100, p...@informatimago.com (Pascal J.
Bourguignon) said:

> Indeed. But my point is that in a conformant program, X wouldn't be
> of an extension type. X here would only be of a standard Common Lisp
> type, therefore in the T branch, EQUAL indeed would behave like EQ for
> the remaining Common Lisp types.

I wasn't talking about conformance, I was talking about quality of
implementation. An implementation which makes it extremely hard to
write robust code in this way is a poor implementation, whether or not
it is conformant. In other words, I should be able to write CL code
which does not have to be littered with special-case checks for
non-standard types with odd behaviours under standard operations.

Alessio Stalla

unread,
Oct 17, 2009, 10:19:18 AM10/17/09
to

Ok, I see your point. It's a matter of trade-offs, and different
people might value trade-offs differently.
Imagine an implementation which supports non-CL objects of type X.
It could define EQUAL for objects of type X to always return 42; while
technically being compliant to the CL standard, it would be a very
poor design decision.
It could define it as EQ, and that would give the maximum possible
degree of compatibility with the rest of CL - a wise choice.
But it could also define it as c:memcmp or java:equals (assuming X
represents a C pointer or a Java object), and provide a "reasonable"
equality predicate, which can break some CL code but arguably will not
most of the time. IIRC SBCL had/has a similar problem with extensible
sequences and CONCATENATE-SEQUENCE (which as per the CL standard
should signal a type error if applied to a sequence which is neither a
list nor a vector). I don't think this makes it a poor implementation;
however "poor" is sufficiently generic to allow for different
opinions.

In the end, my doubt was only about conformance, and I can say it is
now solved.

Alessio

Pascal Costanza

unread,
Oct 17, 2009, 11:02:47 AM10/17/09
to

java:equals would be a good choice only if you also sure that
java:hash-code is used in the right places!

Scott Burson

unread,
Oct 17, 2009, 4:06:55 PM10/17/09
to
On Oct 17, 3:54 am, Tim Bradshaw <t...@cley.com> wrote:

Oh, of course. My point wasn't really about the design of CL, which
as you say was constrained by existing code. I was just giving an
example of how adding a qualifier to the word "equal", in the name of
an equivalence relation other than equality, can clarify the intent of
the relation as well as emphasize that it is not true equality.

-- Scott

Tim Bradshaw

unread,
Oct 17, 2009, 4:33:44 PM10/17/09
to
On 2009-10-17 21:06:55 +0100, Scott Burson <fset...@gmail.com> said:

> Oh, of course. My point wasn't really about the design of CL, which
> as you say was constrained by existing code. I was just giving an
> example of how adding a qualifier to the word "equal", in the name of
> an equivalence relation other than equality, can clarify the intent of
> the relation as well as emphasize that it is not true equality.

I agree with that. In fact there isn't really a general notion of
equality at all (I think someone else has mentioned the KMP article
about this?), so pretty much any definition should be so qualified
really.

Scott Burson

unread,
Oct 17, 2009, 5:00:34 PM10/17/09
to
On Oct 16, 10:44 pm, Raffael Cavallaro
<raffaelcavall...@pas.espam.s.il.vous.plait.mac.com> wrote:

> On 2009-10-17 00:53:36 -0400, Scott Burson <fset....@gmail.com> said:
>
> > Quite the contrary: the authors seem to feel they understand the
> > solution.
>
> Yes, but the "solution" is for the language implementor not to pretend
> that there is one true comparison/copy semantics:
>
> "The language should not provide separate public methods for shallow
> and deep copying and comparison, but only one copy method and one
> comparison method for each class. The designer of the class, rather
> than its clients, should choose appropriate semantics for these
> methods."
>
> (i.e., the class's programmer *not* the language designer and *not* the
> client determines the semantics of "equal" and "copy.")

Hmm, okay. I see that I don't agree with these authors exactly. The
way I like to do things, there is a fixed, completely generic
definition of equality, which follows the rule I gave earlier and
which the authors state in the passage I pointed out on p. 10 (perhaps
they state it better than I do by invoking the notion of abstract
value in place of type-and-content). With this notion of equality,
there is no nontrivial notion of copying. The definition of copying
is to return an equal entity, but the only entity equal to an object
is itself (since equality on objects is identity), and there's no
point in copying a value, because they're not mutable anyway. So the
only "copy" operation that corresponds to this definition of equality
is the identity function.

To put it differently, the only thing you'd ever want to copy is a
mutable object, so that you can then modify one of the copies without
affecting the other. So, I argue, whatever equivalence relation
applies between the object and its copy should not be called simply
"equal", though it could be called "foo-equal" for some "foo". Then
the corresponding copy operation can be called "copy-foo".

Understand that this is fundamentally a stylistic argument. I am
saying that both one's code and one's thinking can be clarified by
following the rules I am setting forth. But the argument does have
implications for language design as well as coding practice, if only
because any practical language has to have some predefined datatypes
(no one really wants to program in pure lambda calculus :).

> IOW, determination of object equality is entirely dependent on the
> intended program semantics. You feel that there is one obviously
> correct semantics which is a functional one - if objects are mutable,
> equality is identity, if immutable, equality is recursive comparison.

Let me repeat, I am NOT saying this is the only equivalence relation
anyone would ever want to use. I am saying this is the only one that
should be CALLED simply "equality" with no qualifier. Again, it's a
stylistic point, but one that I feel is valuable.

-- Scott

Alessio Stalla

unread,
Oct 17, 2009, 7:33:14 PM10/17/09
to
On Oct 17, 5:02 pm, Pascal Costanza <p...@p-cos.net> wrote:
> java:equals would be a good choice only if you also sure that
> java:hash-code is used in the right places!

Yes, of course. The right places being #'equal hash-tables.

Thomas F. Burdick

unread,
Oct 18, 2009, 6:59:02 AM10/18/09
to
On Oct 14, 11:20 pm, Alessio Stalla <alessiosta...@gmail.com> wrote:
> The hyperspec says of EQUAL that it behaves like EQ for every object
> except in a bunch of special cases.
> Does this mean that no conforming Common Lisp implementation can
> extend EQUAL to meaningfully compare implementation-specific objects
> (e.g., Java objects in ABCL or C values in C-based implementations,
> etc)?
> This sounds like a serious limitation to me; among other things, it
> makes it impossible for such implementation-specific objects to be
> treated as first-class Lisp objects - they cannot be seamlessly used
> as keys in a hash-map, for example. Is there a reason for this, or was
> it an overlook at the time the standard was written?

Defining methods on CL:EQUAL wouldn't magically make hash-tables do
what you want. It would just break them.

Equality in CL is not broken, it just works a bit differently than
what you're expecting. Change your expectations to match the language
and you'll be able to figure out how to do what you want. Hint: it's
not impossible. Another hint: intern your foreign objects based on
whatever equality discipline it is that you want, *then* they'll be
truly first-class objects.

Raffael Cavallaro

unread,
Oct 18, 2009, 4:36:50 PM10/18/09
to
On 2009-10-17 17:00:34 -0400, Scott Burson <fset...@gmail.com> said:

> Understand that this is fundamentally a stylistic argument. I am
> saying that both one's code and one's thinking can be clarified by
> following the rules I am setting forth.

Let me preface this by saying that what follows is not intended for
Scott who clearly understands these issues.

A large part of the clarification that Scott is talking about is the
clarification one gets from functional programming - the guarantee that
calling the same function on the same arguments at any point in program
execution returns the same value, the ability this gives us to
understand functions independently, without whole program analysis.

How can we define equal on mutable objects so that equal is functional,
so that it always returns the same result when called on the same args,
even when those args are mutable? The answer is to define our
functional equal to operate on the one thing about mutable objects that
is immutable, namely, their identity.

However, for many object oriented programmers, who use so much mutation
of state that writing programs functionally is more or less out of the
question, it's more convenient for their default equality for mutable
objects to be based on comparing their contents, not their identity,
and it incurs no real costs for them.

IOW, if "equal" is defined in such a way that understanding its
invocation requires whole program analysis, this is a disaster for a
functional program. OTOH, it's of no consequence at all for the typical
OO programmer whose programs almost always require whole program
analysis to understand anyway. (Ha ha, only serious)


> Let me repeat, I am NOT saying this is the only equivalence relation
> anyone would ever want to use.

Yes, I didn't think that you were saying this. The whole discussion has
been about what the default meaning of "equality" should be. You favor
a functional definition but others will prefer a default that is not
functional.

For others reading who may be unfamiliar with these issues, you might
want to look at Henry Baker's paper on the subject:

<http://home.pipeline.com/~hbaker1/ObjectIdentity.html>

regards,

Ralph


--
Raffael Cavallaro

0 new messages