0

I am having trouble understanding how to compare numbers by value vs by address. I have tried the following:

(setf number1 5)
(setf number2 number1)
(setf number3 5)
(setf list1 '(a b c d) )
(setf list2 list1)
(setf list3 '(a b c d) )

I then used the following predicate functions:

>(eq list1 list2) T
>(eq list1 list3) Nil
>(eq number1 number2) T
>(eq number1 number3) T

Why is it that with lists eq acts like it should (both pointers for list1 and list3 are different) yet for numbers it does not act like I think it should as number1 and number3 should have different addresses. Thus my question is why this doesn't act like I think it should and if there is a way to compare addresses of variables containing numbers vs values.

JmanxC
  • 377
  • 2
  • 16
  • Possible duplicate of [What's the difference between eq, eql, equal, and equalp in Common Lisp?](http://stackoverflow.com/questions/547436/whats-the-difference-between-eq-eql-equal-and-equalp-in-common-lisp) – sds Jun 15 '16 at 21:07

2 Answers2

5

Equality Predicates in Common Lisp

how to compare numbers by value vs by address.

While there's a sense in which can be applied, that's not really the model that Common Lisp provides. Reading about the built-in equality predicates can help clarify the way in which objects are stored in memory (implicitly)..

EQ is generally what checks the "same address", but that's not how it's specified, and that's not exactly what it does, either. It "returns true if its arguments are the same, identical object; otherwise, returns false."

What does it mean to be the same identical object? For things like cons-cells (from which lists are built), there's an object in memory somewhere, and eq checks whether two values are the same object. Note that eq could return true or false on primitives like numbers, since the implementation is free to make copies of them.

EQL is like eq, but it adds a few extra conditions for numbers and characters. Numbers of the same type and value are guaranteed to be eql, as are characters that represent the same character.

EQUAL and EQUALP are where things start to get more complex and you actually get something like element-wise comparison for lists, etc.

This specific case

Why is it that with lists eq acts like it should (both pointers for list1 and list3 are different) yet for numbers it does not act like I think it should as number1 and number3 should have different addresses. Thus my question is why this doesn't act like I think it should and if there is a way to compare addresses of variables containing numbers vs values.

The examples in the documentation for eq show that (eq 3 3) (and thus, (let ((x 3) (y 3)) (eq x y)) can return true or false. The behavior you're observing now isn't the only possible one.

Also, note that in compiled code, constant values can be coalesced into one. That means that the compiler has the option of making the following return true:

(let ((x '(1 2 3))
      (y '(1 2 3)))
   (eq x y))
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • I just tried that code and it gives me true, when would it be the case that it returns false? – JmanxC Jun 15 '16 at 20:58
  • @JManx Which code? I posted two parts of code (the inline and a code block at the end). But as I said, there are examples in the documentation for EQ. It's not a matter of when one happens or the other happens, the point is that *either* could happen. – Joshua Taylor Jun 15 '16 at 20:59
  • The code from the documentation. The first let with numbers,not the list. – JmanxC Jun 15 '16 at 21:00
  • @Jmanx It depends on what the implementation does. It could do either. The point is that you don't have a portable way to make one or the other happen; it's up to the implementation. If you want a "value cell" in which store a number, and you want the ability to check whether the cells (as opposed to the values in them) are the same, you need to use some object with identity to do that. E.g., a list or vector of length 1. – Joshua Taylor Jun 15 '16 at 21:02
  • So what I am understanding is that there is no clear function to compare variables containing numbers,other then by value. Another implementation would be needed to do so. Yet for lists functions like eq work effectively? – JmanxC Jun 15 '16 at 21:10
  • @jmanxc there's no real concept of variable as a storage location at runtime. There are values which are either equivalent (under different equality predicates) or not. In that sense, Java and other languages without pointers are like this, too. – Joshua Taylor Jun 15 '16 at 21:14
  • @jmanxc What use case would this enable in the language? I'm not really clear how this came up? Often times, understanding the original motivation can help in explaining the current behavior. – Joshua Taylor Jun 15 '16 at 21:16
  • I just find it a weird concept to comprehend as in java such methods as .equals does compare object addresses for any data type,be it numbers,arrays,linked lists etc. Yet here it straight up looks like it only compares by value when the variable stores a number. Guess functional programming just takes some getting used to as even the documentation i find incredibly vague when they say "=> or" .equal in java for instance always compares objects and its implementation is never changed at less overridden, this includes using Integer values. – JmanxC Jun 15 '16 at 21:21
  • @jmancx common lisp's eq is like java's ==, and in java, two Strings or Integers might not be == even when they are .equals(). – Joshua Taylor Jun 15 '16 at 21:29
  • Back to being confused haha, I thought lisps = and equal was comparable to == in java. Such as (if (= n 0) do this...) vs if (n == 0) do this. Anyways I guess I should just start treating lisp as being completely different than java. Moving between different OOP languages is simple, but it seems moving from an OOP language to a functional programming language,is a different story. – JmanxC Jun 15 '16 at 21:36
  • 1
    @jmanxc common lisp and Java are actually rather similar in many ways (e.g., in "everything's a reference"). And common lisp has an OO system (CLOS) that's a bit more powerful than java's. and while lisp may support functional programming, it's not a functional programming language any more than it is a an oo language – Joshua Taylor Jun 15 '16 at 21:39
  • 2
    @JmanxC The best "short and concise" name for the type of programming language that Common Lisp is is "multi-paradigm". It's not "functional", but supports writing functional code. It's not OO, but supports writing OO code, ... As for `eq` with numbers, most (if possibly not all) Cl implementations will have two integers compare as equal with `eq` iff they're fixnums. That's typically numbers that are a few bits shorter than the word size of the implementation (exactly how many bits shorter depends both on how the type tagging is done and the actual word size). – Vatine Jun 16 '16 at 10:02
2

One of the problems is that testing it in one implementation in a specific setting does not tell you much. Implementations may behave differently when the ANSI Common Lisp specification allows it.

  1. do not assume that two numbers of the same value are EQ or not EQ. This is unspecified in Common Lisp. Use EQL or = to compare numbers.

  2. do not assume that two literal lists, looking similar in a printed representation, are EQ or not EQ. This is unspecified in Common Lisp for the general case.

For example:

A file with the following content:

(defvar *a* '(1 2 3))
(defvar *b* '(1 2 3))

If one now compiles and loads the file it is unspecified if (eq *a* *b*) is T or NIL. Common Lisp allows an optimizing compiler to detect that the lists have the similar content and then will allocate only one list and both variables will be bound to the same list.

An implementation might even save space when not the whole lists are having similar content. For example in (a 1 2 3 4) and (b 1 2 3 4) a sublist (1 2 3 4) could be shared.

For code with a lot of list data, this could help saving space both in code and memory. Other implementations might not be that sophisticated. In interactive use, it is unlikely that an implementation will try to save space like that.

In the Common Lisp standard quite a bit behavior is unspecified. It was expected that implementations with different goals might benefit from different approaches.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346