#lang scribble/manual
@(require (only-in scribblings/style/shared compare)
          "mz.rkt")


@title{Equality}


Equality is the concept of whether two values are ``the same.'' Racket supports
a few different kinds of equality by default, although @racket[equal?] is
preferred for most uses.

@defproc[(equal? [v1 any/c] [v2 any/c]) boolean?]{

 Two values are @racket[equal?] if and only if they are @racket[eqv?],
 unless otherwise specified for a particular datatype.

 Datatypes with further specification of @racket[equal?] include
 strings, byte strings, pairs, mutable pairs, vectors, boxes, hash
 tables, and inspectable structures. In the last six cases, equality
 is recursively defined; if both @racket[v1] and @racket[v2] contain
 reference cycles, they are equal when the infinite unfoldings of the
 values would be equal. See also @racket[gen:equal+hash] and
 @racket[prop:impersonator-of].

 @(examples
   (equal? 'yes 'yes)
   (equal? 'yes 'no)
   (equal? (* 6 7) 42)
   (equal? (expt 2 100) (expt 2 100))
   (equal? 2 2.0)
   (let ([v (mcons 1 2)]) (equal? v v))
   (equal? (mcons 1 2) (mcons 1 2))
   (equal? (integer->char 955) (integer->char 955))
   (equal? (make-string 3 #\z) (make-string 3 #\z))
   (equal? #t #t))}


@defproc[(equal-always? [v1 any/c] [v2 any/c]) boolean?]{

 Indicates whether @racket[v1] and @racket[v2] are equal and will always stay
 equal independent of @emph{mutations}. Generally, for to values to be equal-always, corresponding
 immutable values within @racket[v1] and @racket[v2] must be @racket[equal?],
 while corresponding mutable values within them must be @racket[eq?].

 Two values @racket[v1] and @racket[v2] are @racket[equal-always?] if and only
 if there exists a third value @racket[_v3] such that @racket[v1] and
 @racket[v2] are both chaperones of @racket[_v3], meaning
 @racket[(chaperone-of? v1 _v3)] and @racket[(chaperone-of? v2 _v3)] are both
 true.

 For values that include no chaperones or other impersonators,
 @racket[v1] and @racket[v2] can be considered equal-always
 if they are @racket[equal?], except that corresponding mutable
 vectors, boxes, hash tables, strings, byte strings, @tech{mutable pairs}, and
 mutable structures within
 @racket[v1] and @racket[v2] must be @racket[eq?], and equality on structures
 can be specialized for @racket[equal-always?] through @racket[gen:equal-mode+hash].

 @(examples
   (equal-always? 'yes 'yes)
   (equal-always? 'yes 'no)
   (equal-always? (* 6 7) 42)
   (equal-always? (expt 2 100) (expt 2 100))
   (equal-always? 2 2.0)
   (equal-always? (list 1 2) (list 1 2))
   (let ([v (mcons 1 2)]) (equal-always? v v))
   (equal-always? (mcons 1 2) (mcons 1 2))
   (equal-always? (integer->char 955) (integer->char 955))
   (equal-always? (make-string 3 #\z) (make-string 3 #\z))
   (equal-always? (string->immutable-string (make-string 3 #\z))
                  (string->immutable-string (make-string 3 #\z)))
   (equal-always? #t #t))

@history[#:added "8.5.0.3"]}


@defproc[(eqv? [v1 any/c] [v2 any/c]) boolean?]{

 Two values are @racket[eqv?] if and only if they are @racket[eq?],
 unless otherwise specified for a particular datatype.

 The @tech{number} and @tech{character} datatypes are the only ones for which
 @racket[eqv?] differs from @racket[eq?]. Two numbers are @racket[eqv?] when
 they have the same exactness, precision, and are both equal and non-zero, both
 @racketvalfont{+0.0}, both @racketvalfont{+0.0f0}, both @racketvalfont{-0.0},
 both @racketvalfont{-0.0f0}, both @racketvalfont{+nan.0}, or both
 @racketvalfont{+nan.f}---considering real and imaginary components separately
 in the case of @tech{complex numbers}. Two characters are @racket[eqv?] when
 their @racket[char->integer] results are equal.

 Generally, @racket[eqv?] is identical to @racket[equal?] except that the former
 cannot recursively compare the contents of compound data types (such as lists
 and structs) and cannot be customized by user-defined data types. The use of
 @racket[eqv?] is lightly discouraged in favor of @racket[equal?].

 @(examples
   (eqv? 'yes 'yes)
   (eqv? 'yes 'no)
   (eqv? (* 6 7) 42)
   (eqv? (expt 2 100) (expt 2 100))
   (eqv? 2 2.0)
   (let ([v (mcons 1 2)]) (eqv? v v))
   (eqv? (mcons 1 2) (mcons 1 2))
   (eqv? (integer->char 955) (integer->char 955))
   (eqv? (make-string 3 #\z) (make-string 3 #\z))
   (eqv? #t #t))}


@defproc[(eq? [v1 any/c] [v2 any/c]) boolean?]{

 Return @racket[#t] if @racket[v1] and @racket[v2] refer to the same
 object, @racket[#f] otherwise. As a special case among @tech{numbers},
 two @tech{fixnums} that are @racket[=] are also the same according
 to @racket[eq?]. See also @secref["model-eq"].

 @(examples
   (eq? 'yes 'yes)
   (eq? 'yes 'no)
   (eq? (* 6 7) 42)
   (eq? (expt 2 100) (expt 2 100))
   (eq? 2 2.0)
   (let ([v (mcons 1 2)]) (eq? v v))
   (eq? (mcons 1 2) (mcons 1 2))
   (eq? (integer->char 955) (integer->char 955))
   (eq? (make-string 3 #\z) (make-string 3 #\z))
   (eq? #t #t))}


@defproc[
 (equal?/recur [v1 any/c] [v2 any/c] [recur-proc (any/c any/c -> any/c)])
 boolean?]{

 Like @racket[equal?], but using @racket[recur-proc] for recursive
 comparisons (which means that reference cycles are not handled
 automatically). Non-@racket[#f] results from @racket[recur-proc] are
 converted to @racket[#t] before being returned by
 @racket[equal?/recur].

 @(examples
   (equal?/recur 1 1 (lambda (a b) #f))
   (equal?/recur '(1) '(1) (lambda (a b) #f))
   (equal?/recur '#(1 1 1) '#(1 1.2 3/4)
                 (lambda (a b) (<= (abs (- a b)) 0.25))))}


@defproc[
 (equal-always?/recur [v1 any/c] [v2 any/c] [recur-proc (any/c any/c -> any/c)])
 boolean?]{

 Like @racket[equal-always?], but using @racket[recur-proc] for recursive
 comparisons (which means that reference cycles are not handled
 automatically). Non-@racket[#f] results from @racket[recur-proc] are
 converted to @racket[#t] before being returned by
 @racket[equal-always?/recur].

 @(examples
   (equal-always?/recur 1 1 (lambda (a b) #f))
   (equal-always?/recur '(1) '(1) (lambda (a b) #f))
   (equal-always?/recur (vector-immutable 1 1 1) (vector-immutable 1 1.2 3/4)
                        (lambda (a b) (<= (abs (- a b)) 0.25))))}


@section[#:tag "model-eq"]{Object Identity and Comparisons}


The @racket[eq?] operator compares two @tech{values}, returning
@racket[#t] when the values refer to the same @tech{object}. This form
of equality is suitable for comparing objects that support imperative
update (e.g., to determine that the effect of modifying an object
through one reference is visible through another reference). Also, an
@racket[eq?] test evaluates quickly, and @racket[eq?]-based hashing
is more lightweight than @racket[equal?]-based hashing in hash tables.

In some cases, however, @racket[eq?] is unsuitable as a comparison
operator, because the generation of @tech{objects} is not clearly
defined. In particular, two applications of @racket[+] to the same two
exact integers may or may not produce results that are @racket[eq?],
although the results are always @racket[equal?]. Similarly, evaluation
of a @racket[lambda] form typically generates a new procedure
@tech{object}, but it may re-use a procedure @tech{object} previously
generated by the same source @racket[lambda] form.

The behavior of a datatype with respect to @racket[eq?] is generally
specified with the datatype and its associated procedures.


@section{Equality and Hashing}


All comparable values have at least one @deftech{hash code} --- an arbitrary
integer (more specifically a @tech{fixnum}) computed by applying a hash function
to the value. The defining property of these hash codes is that @bold{equal
 values have equal hash codes}. Note that the reverse is not true: two unequal
values can still have equal hash codes. Hash codes are useful for various
indexing and comparison operations, especially in the implementation of
@tech{hash tables}. See @secref["hashtables"] for more information.


@defproc[(equal-hash-code [v any/c]) fixnum?]{

 Returns a @tech{hash code} consistent with @racket[equal?]. For any two calls
 with @racket[equal?] values, the returned number is the same. A hash code is
 computed even when @racket[v] contains a cycle through pairs, vectors, boxes,
 and/or inspectable structure fields. Additionally, user-defined data types can
 customize how this hash code is computed by implementing
 @racket[gen:equal+hash] or @racket[gen:equal-mode+hash].

 For any @racket[v] that could be produced by @racket[read], if @racket[v2] is
 produced by @racket[read] for the same input characters, the
 @racket[(equal-hash-code v)] is the same as @racket[(equal-hash-code v2)] ---
 even if @racket[v] and @racket[v2] do not exist at the same time (and therefore
 could not be compared by calling @racket[equal?]).

 @history[
 #:changed "6.4.0.12"
 @elem{Strengthened guarantee for @racket[read]able values.}]}


@defproc[(equal-secondary-hash-code [v any/c]) fixnum?]{

 Like @racket[equal-hash-code], but computes a secondary @tech{hash code}
 suitable for use in double hashing.}


@defproc[(equal-always-hash-code [v any/c]) fixnum?]{

 Returns a @tech{hash code} consistent with @racket[equal-always?]. For any two
 calls with @racket[equal-always?] values, the returned number is the same.

 As @racket[equal-always-hash-code] traverses @racket[v], immutable
 values within @racket[v] are hashed with @racket[equal-hash-code],
 while mutable values within @racket[v] are hashed with @racket[eq-hash-code].}


@defproc[(equal-always-secondary-hash-code [v any/c]) fixnum?]{

 Like @racket[equal-always-hash-code], but computes a secondary @tech{hash code}
 suitable for use in double hashing.}


@defproc[(eq-hash-code [v any/c]) fixnum?]{

 Returns a @tech{hash code} consistent with @racket[eq?]. For any two calls with
 @racket[eq?] values, the returned number is the same.

 @margin-note{Equal @tech{fixnums} are always @racket[eq?].}}


@defproc[(eqv-hash-code [v any/c]) fixnum?]{

 Returns a @tech{hash code} consistent with @racket[eqv?]. For any two calls
 with @racket[eqv?] values, the returned number is the same.}


@section{Implementing Equality for Custom Types}


@defthing[gen:equal+hash any/c]{
 A @tech{generic interface} (see @secref["struct-generics"]) for types that can
 be compared for equality using @racket[equal?]. The following methods must be
 implemented:

 @itemize[

 @item{@racket[_equal-proc :
               (any/c any/c (any/c any/c . -> . boolean?)  . -> . any/c)] ---
   tests whether the first two arguments are equal, where both values are
   instances of the structure type to which the generic interface is associated
   (or a subtype of the structure type).

   The third argument is an @racket[equal?]  predicate to use for
   recursive equality checks; use the given predicate instead of
   @racket[equal?] to ensure that data cycles are handled
   properly and to work with @racket[equal?/recur] (but beware
   that an arbitrary function can be provided to
   @racket[equal?/recur] for recursive checks, which means that
   arguments provided to the predicate might be exposed to
   arbitrary code).

   The @racket[_equal-proc] is called for a pair of structures
   only when they are not @racket[eq?], and only when they both
   have a @racket[gen:equal+hash] value inherited from the same
   structure type. With this strategy, the order in which
   @racket[equal?] receives two structures does not matter. It
   also means that, by default, a structure sub-type inherits the
   equality predicate of its parent, if any.}

 @item{@racket[_hash-proc :
               (any/c (any/c . -> . exact-integer?) . -> . exact-integer?)] ---
   computes a hash code for the given structure, like @racket[equal-hash-code].
   The first argument is an instance of the structure type (or one of its
   subtypes) to which the generic interface is associated.

   The second argument is an @racket[equal-hash-code]-like procedure to use for
   recursive hash-code computation; use the given procedure instead of
   @racket[equal-hash-code] to ensure that data cycles are handled properly.

   Although the result of @racket[_hash-proc] can be any exact
   integer, it will be truncated for most purposes to a @tech{fixnum}
   (e.g., for the result of @racket[equal-hash-code]). Roughly,
   truncation uses @racket[bitwise-and] to take the lower bits of the
   number. Thus, variation in the hash-code computation should be
   reflected in the fixnum-compatible bits of @racket[_hash-proc]'s
   result. Consumers of a hash code are expected to use variation
   within the fixnum range appropriately, and producers are @emph{not}
   responsible to reflect variation in hash codes across the full
   range of bits that fit within a fixnum.}

 @item{@racket[_hash2-proc :
               (any/c (any/c . -> . exact-integer?) . -> . exact-integer?)] ---
   computes a secondary hash code for the given structure. This procedure is
   like @racket[_hash-proc], but analogous to
   @racket[equal-secondary-hash-code].}]

 Take care to ensure that @racket[_hash-proc] and @racket[_hash2-proc]
 are consistent with @racket[_equal-proc]. Specifically,
 @racket[_hash-proc] and @racket[_hash2-proc] should produce the same
 value for any two structures for which @racket[_equal-proc] produces a
 true value.

 The @racket[_equal-proc] is not only used for
 @racket[equal?], it is also used for @racket[equal?/recur],
 and @racket[impersonator-of?]. Furthermore, if the structure type
 has no mutable fields, @racket[_equal-proc] is used for @racket[equal-always?], and
 @racket[chaperone-of?]. Likewise @racket[_hash-proc] and
 @racket[_hash2-proc] are used for
 @racket[equal-always-hash-code] and
 @racket[equal-always-secondary-hash-code], respectively, when
 the structure type has no mutable fields.
 Instances of these methods should follow the guidelines in
 @secref["Honest_Custom_Equality"] to implement all of these
 operations reasonably. In particular, these methods should
 not access mutable data unless the struct is declared
 mutable.

 When a structure type has no @racket[gen:equal+hash] or
 @racket[gen:equal-mode+hash] implementation, then
 transparent structures (i.e., structures with an @tech{inspector} that
 is controlled by the current @tech{inspector}) are @racket[equal?]
 when they are instances of the same structure type (not counting
 sub-types), and when they have @racket[equal?] field values.  For
 transparent structures, @racket[equal-hash-code] and
 @racket[equal-secondary-hash-code] (in the case of no mutable fields)
 derive hash code using the field
 values. For a transparent structure type with at least one mutable field,
 @racket[equal-always?] is the same as @racket[eq?], and an
 @racket[equal-secondary-hash-code] result is based only on @racket[eq-hash-code].
 For opaque structure types, @racket[equal?] is the same as
 @racket[eq?], and @racket[equal-hash-code] and
 @racket[equal-secondary-hash-code] results are based only on
 @racket[eq-hash-code]. If a structure has a @racket[prop:impersonator-of]
 property, then the @racket[prop:impersonator-of] property takes precedence over
 @racket[gen:equal+hash] if the property value's procedure returns a
 non-@racket[#f] value when applied to the structure.

 @(examples
   (eval:no-prompt
    (define (farm=? farm1 farm2 recursive-equal?)
      (and (= (farm-apples farm1)
              (farm-apples farm2))
           (= (farm-oranges farm1)
              (farm-oranges farm2))
           (= (farm-sheep farm1)
              (farm-sheep farm2))))

    (define (farm-hash-code farm recursive-equal-hash)
      (+ (* 10000 (farm-apples farm))
         (* 100 (farm-oranges farm))
         (* 1 (farm-sheep farm))))

    (define (farm-secondary-hash-code farm recursive-equal-hash)
      (+ (* 10000 (farm-sheep farm))
         (* 100 (farm-apples farm))
         (* 1 (farm-oranges farm))))

    (struct farm (apples oranges sheep)
      #:methods gen:equal+hash
      [(define equal-proc farm=?)
       (define hash-proc  farm-hash-code)
       (define hash2-proc farm-secondary-hash-code)])

    (define eastern-farm (farm 5 2 20))
    (define western-farm (farm 18 6 14))
    (define northern-farm (farm 5 20 20))
    (define southern-farm (farm 18 6 14)))

   (equal? eastern-farm western-farm)
   (equal? eastern-farm northern-farm)
   (equal? western-farm southern-farm))}


@defthing[gen:equal-mode+hash any/c]{
 A @tech{generic interface} (see @secref["struct-generics"]) for types that
 may specify differences between @racket[equal?] and @racket[equal-always?].
 The following methods must be implemented:

 @itemlist[

 @item{@racket[_equal-mode-proc :
               (any/c any/c (any/c any/c . -> . boolean?) boolean? . -> . any/c)] ---
   the first two arguments are the values to compare, the third argument is an
   equality function to use for recursive comparisons, and the last argument is
   the mode: @racket[#t] for an @racket[equal?] or @racket[impersonator-of?]
   comparison or @racket[#f] for an @racket[equal-always?] or
   @racket[chaperone-of?] comparison.}

 @item{@racket[_hash-mode-proc :
               (any/c (any/c . -> . exact-integer?) boolean? . -> . exact-integer?)] ---
   the first argument is the value to compute a hash code for, the second
   argument is a hashing function to use for recursive hashing, and the last
   argument is the mode: @racket[#t] for @racket[equal?] hashing or @racket[#f]
   for @racket[equal-always?] hashing.}]

 The @racket[_hash-mode-proc] implementation is used both for a
 primary hash code and secondary hash code.

 When implementing these methods, follow the guidelines in
 @secref["Honest_Custom_Equality"]. In particular, these
 methods should only access mutable data if the ``mode'' argument
 is true to indicate @racket[equal?] or @racket[impersonator-of?].

 Implementing @racket[gen:equal-mode+hash] is most useful for types that
 specify differences between @racket[equal?] and @racket[equal-always?], such
 as a structure type that wraps mutable data with getter and setter procedures:
 @(examples
   (define (get gs) ((getset-getter gs)))
   (define (set gs new) ((getset-setter gs) new))
   (struct getset (getter setter)
      #:methods gen:equal-mode+hash
      [(define (equal-mode-proc self other rec mode)
         (and mode (rec (get self) (get other))))
       (define (hash-mode-proc self rec mode)
         (if mode (rec (get self)) (eq-hash-code self)))])

   (define x 1)
   (define y 2)
   (define gsx (getset (lambda () x) (lambda (new) (set! x new))))
   (define gsy (getset (lambda () y) (lambda (new) (set! y new))))
   (eval:check (equal? gsx gsy) #f)
   (eval:check (equal-always? gsx gsy) #f)
   (set gsx 3)
   (set gsy 3)
   (eval:check (equal? gsx gsy) #t)
   (eval:check (equal-always? gsx gsy) #f)
   (eval:check (equal-always? gsx gsx) #t))

@history[#:added "8.5.0.3"]}


@defthing[prop:equal+hash struct-type-property?]{

 A @tech{structure type property} (see @secref["structprops"])
 that supplies an equality predicate and hashing functions for a structure
 type. Using the @racket[prop:equal+hash] property is an alternative to
 using the @racket[gen:equal+hash] or @racket[gen:equal-mode+hash]
 @tech{generic interface}.

 A @racket[prop:equal+hash] property value is a list of either three
 procedures @racket[(list _equal-proc _hash-proc _hash2-proc)] or two
 procedures @racket[(list _equal-mode-proc _hash-mode-proc)]:

 @itemlist[

  @item{The three-procedure case corresponds to the procedures of
        @racket[gen:equal-hash]:

         @itemlist[
           @item{@racket[_equal-proc : (any/c any/c (any/c any/c . -> . boolean?)  . -> . any/c)]}

           @item{@racket[_hash-proc : (any/c (any/c . -> . exact-integer?) . -> . exact-integer?)]}

           @item{@racket[_hash2-proc : (any/c (any/c . -> . exact-integer?) . -> . exact-integer?)]}
        ]}

  @item{The two-procedure case corresponds to the procedures of
  @racket[gen:equal-mode-hash]:

       @itemlist[
         @item{@racket[_equal-mode-proc : (any/c any/c (any/c any/c . -> . boolean?) boolean? . -> . any/c)]}

          @item{@racket[_hash-mode-proc : (any/c (any/c . -> . exact-integer?) boolean? . -> . exact-integer?)]}

        ]}

]

When implementing these methods, follow the guidelines in
@secref["Honest_Custom_Equality"]. In particular, these
methods should only access mutable data if the struct is
declared mutable or the mode is true.

@history[#:changed "8.5.0.3" @elem{Added support for two-procedure values to customize @racket[equal-always?].}]}

@section[#:tag "Honest_Custom_Equality"]{Honest Custom Equality}

Since the @racket[_equal-proc] or @racket[_equal-mode-proc]
is used for more than just @racket[equal?], instances of
them should follow certain guidelines to make sure that they work
correctly for @racket[equal-always?], @racket[chaperone-of?],
and @racket[impersonator-of?].

Due to the differences between these operations, avoid
calling @racket[equal?] within them. Instead, use the third
argument to ``recur'' on the pieces, which allows
@racket[equal?/recur] to work properly, lets the other
operations behave in their own distinct ways on the pieces,
and enables some cycle detection.

@compare[
@filebox[@tt{good}]{
@racketblock0[
  (define (equal-proc self other rec)
    (rec (fish-size self) (fish-size other)))
]}

@filebox[@tt{bad}]{
@racketblock0[
  (define (equal-proc self other rec)
    (equal? (fish-size self) (fish-size other)))
]}
]

The operations @racket[equal?] and @racket[equal-always?]
should be symmetric, so @racket[_equal-proc] instances
should not change their answer when the arguments swap:

@compare[
@filebox[@tt{good}]{
@racketblock0[
  (define (equal-proc self other rec)
    (rec (fish-size self) (fish-size other)))
]}

@filebox[@tt{bad}]{
@racketblock0[
  (define (equal-proc self other rec)
    (<= (fish-size self) (fish-size other)))
]}
]

However, the operations @racket[chaperone-of?] and
@racket[impersonator-of?] are @emph{not} symmetric, so when
calling the third argument to ``recur'' on pieces, pass the
pieces in the same order they came in:

@compare[
@filebox[@tt{good}]{
@racketblock0[
  (define (equal-proc self other rec)
    (rec (fish-size self) (fish-size other)))
]}

@filebox[@tt{bad}]{
@racketblock0[
  (define (equal-proc self other rec)
    (rec (fish-size other) (fish-size self)))
]}
]

Mutable structs will only use the custom equality for
@racket[equal?] and @racket[impersonator-of?], so that
@racket[equal-always?] and @racket[chaperone-of?] don't
change on mutation. Structs that represent mutable data
should either be declared mutable, or use
@racket[_equal-mode-proc] from @racket[gen:equal-mode+hash]
instead of @racket[_equal-proc] from @racket[gen:equal+hash],
and only access mutable data when the mode is true:

@compare[
@filebox[@tt{good}]{
@racketblock0[
  (struct mcell (value) #:mutable
    #:methods gen:equal+hash
    [(define (equal-proc self other rec)
       (rec (mcell-value self)
            (mcell-value other)))
     (define (hash-proc self rec)
       (+ (eq-hash-code struct:mcell)
          (rec (mcell-value self))))
     (define (hash2-proc self rec)
       (+ (eq-hash-code struct:mcell)
          (rec (mcell-value self))))])
]}

@filebox[@tt{bad}]{
@racketblock0[
  (struct mcell (box)
    (code:comment "not declared mutable,")
    (code:comment "but represents mutable data anyway")
    #:methods gen:equal+hash
    [(define (equal-proc self other rec)
       (rec (unbox (mcell-box self))
            (unbox (mcell-box other))))
     (define (hash-proc self rec)
       (+ (eq-hash-code struct:mcell)
          (rec (unbox (mcell-value self)))))
     (define (hash2-proc self rec)
       (+ (eq-hash-code struct:mcell)
          (rec (unbox (mcell-value self)))))])
]}
]

@compare[
@filebox[@tt{also good}]{
@racketblock0[
  (struct mcell (value) #:mutable
    (code:comment "only accesses mutable data when mode is true")
    #:methods gen:equal-mode+hash
    [(define (equal-mode-proc self other rec mode)
       (and mode
            (rec (mcell-value self)
                 (mcell-value other))))
     (define (hash-mode-proc self rec mode)
       (if mode
           (+ (eq-hash-code struct:mcell)
              (rec (mcell-value self)))
           (eq-hash-code self)))])
]}

@filebox[@tt{still bad}]{
@racketblock0[
  (struct mcell (value) #:mutable
    (code:comment "accesses mutable data ignoring mode")
    #:methods gen:equal-mode+hash
    [(define (equal-mode-proc self other rec mode)
       (rec (mcell-value self)
            (mcell-value other)))
     (define (hash-mode-proc self rec mode)
       (+ (eq-hash-code struct:mcell)
          (rec (mcell-value self))))])
]}
]
