Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!dali.cs.montana.edu!caen!sdd.hp.com!wuarchive!udel!rochester!pt.cs.cmu.edu!o.gp.cs.cmu.edu!ram From: ram+@cs.cmu.edu (Rob MacLachlan) Newsgroups: comp.lang.lisp Subject: Re: Eternal fixnum question (was Re: GET / GETF warning.) Message-ID: <1991May1.015534.27054@cs.cmu.edu> Date: 1 May 91 01:55:34 GMT References: <641@zogwarg.etl.army.mil> <4580@skye.ed.ac.uk> Sender: netnews@cs.cmu.edu (USENET News Group Software) Organization: School of Computer Science, Carnegie Mellon Lines: 60 In article <4580@skye.ed.ac.uk> jeff@aiai.UUCP (Jeff Dalton) writes: > >I suppose this isn't the _best_ place to raise this question, >but when EQ, fixnums, and FAQ appear in the same place it's >almost irresistible. > >As you all will recall, Common Lisp allows EQ to return false >for fixnums that are EQL. > >[2] (let ((x 5)) (eq x x)) ; CLtL II p 104 > >What's hard to see >is why in any reasonable implementation [1] or [2] would actually turn >out to be false. This is more convincing with floats, since fixnums normally have immediate representations in modern lisps, but here is the scenario: -- X is known to be a fixnum, so the compiler allocates in a register without any tag bits. This is an unboxed (or non-descriptor) representation. -- The compiler notices some references to X in contexts that require a tagged Lisp object. For each such reference, it heap allocates a copy of X. -- This results in EQ being passed two difference copies of X. Now, you might argue that this is a rather silly thing for the compiler to do, especially when both arguments are known to be fixnums. But consider something like: (let ((x 1)) (eq x (if yow x (gloob)))) Basically, there was a langauge design tradoff here. Is it more important to have a well-defined pointer identity for numbers, or is it more important to be able to generate tense numeric code? The only way to ensure that pointer identity is preserved for numbers would be to always retain the original object pointer, as well as any untagged value, and then to use the original object pointer in any tagged context. But this causes nasty problems with set variables: (let ((x z) (y z)) (declare (fixnum x y)) (when (gloob) (setq x (+ x (the fixnum grue)))) (eq x y)) Now what to you do? Keep a shadow tagged X, but invalidate it whenever it is set, and then cons X at the EQ when the shadow X is invalidated? Cons the result of + just so that you can store it into the shadow X? If this were an important problem to solve, I'm sure a solution could be worked out that wouldn't be too terribly inefficient most of the time, but why bother? As near as I can tell, object identity (EQ) is only an important operation on objects which can be side-effected, and numbers can't. You can also use EQ as a probabilistic optimization of general equality: if two objects are EQ, they are definitely the same. If not, they might be the same. But number copying only makes this hint slightly less sucessful, it doesn't break the semantics. Robert MacLachlan (ram@cs.cmu.edu)