How does eq? in Racket work?

lisp, racket, scheme

Solution

For a technical explanation of how `eq?` works, take a look at the current specification, you won't find a more detailed reference. Or simply check Racket's documentation on the subject, in particular the procedures `eq?`, `eqv?` and `equal?`. Regarding your question - the result is as expected and correct in the Scheme code, let's see why. Notice that in this line in Java:

p1.x = 42;

You're modifying the same object that's being pointed at by both `p1` and `p2`. Whereas in this line:

(set! cons1 (cons 2 empty))

You're creating a new, different object and setting `cons1` to point to it, but `cons2` is still pointing to the old object. You can confirm this, after the previous line, the comparison `(eq? cons1 cons2)` will return `#f`.

The point is: the examples are not equivalent. The Java example deals with a single object that's being pointed at by two different references, whereas the Scheme example deals with two objects and two references.

For comparison purposes, here's a Scheme example that's similar to the Java code, and works as you expected because in here we're modifying a single mutable object that's being pointed at by two references:

#lang racket
(require scheme/mpair) ;; `m` stands for "mutable"

(define p1 (mlist 5 5))
(define p2 p1)

(eq? p1 p2)       ;; #t
(mcar p1)         ;;  5
(mcar p2)         ;;  5

(set-mcar! p1 42)
(eq? p1 p2)       ;; #t
(mcar p1)         ;; 42
(mcar p2)         ;; 42

Problem

At my university we had to work with Racket and since I kind of liked it, I bought the recently published book "Realm Of Racket" from No Starch. It's great so far, however, I cannot figure out what they mean in Chapter 4 when they try to explain how eq? works: - At first, they explain how equal? compares whether two values consist of identical pieces. OK, no problem, I got that: equal? does pretty much the same thing as Java's equals(someObject) method. If two objects/structs/whatever are the same contentwise, #t is being returned. - Then, I figured, eq? must be the equivalent to Java's == operator, which doesn't compare contentwise but based on references. This thought seemed to be confirmed by the following sentence in the book: "eq? compares whether changing one structure changes the other structure..." Great! Let's compare it to the following piece of Java code: ``` Point p1 = new Point(5, 5); Point p2 = p1; System.out.println(p1 == p2); // true, since the reference has been copied. System.out.println(p1.x); // 5 System.out.println(p2.x); // 5 p1.x = 42; System.out.println(p1.x); // 42 System.out.println(p2.x); // Accordingly, 42 ``` Let's try this in Racket: ``` (define cons1 (cons 1 empty)) (define cons2 cons1) (eq? cons1 cons2) ;; #t, since the refernce has been copied. (set! cons1 (cons 2 empty)) cons1 ;; Returns '(2) - as expected. cons2 ;; Still returns '(1). ``` Why? cons2 points to cons1, which itself points to '(2). Additionally, didn't they just say that they are equal as soon as one changes the other? Obviously, right now I don't get why this doesn't behave as expected and because of that, I don't see what eq? is doing. Maybe I am wrong and it does not have anything to do with references... If someone knows about this, please share your wisdom ;)

Original source