6.8 Object Equality and Hashing

► |  | The Racket Reference

1 | Language Model
2 | Notation for Documentation
3 | Syntactic Forms
4 | Datatypes
5 | Structures
6 | Classes and Objects
7 | Units
8 | Contracts
9 | Pattern Matching
10 | Control Flow
11 | Concurrency and Parallelism
12 | Macros
13 | Input and Output
14 | Reflection and Security
15 | Operating System
16 | Memory Management
17 | Unsafe Operations
18 | Running Racket
| Bibliography
| Index

▼ | 6 | Classes and Objects

6.1 | Creating Interfaces
6.2 | Creating Classes
6.3 | Creating Objects
6.4 | Field and Method Access
6.5 | Mixins
6.6 | Traits
6.7 | Object and Class Contracts
6.8 | Object Equality and Hashing
6.9 | Object Serialization
6.10 | Object Printing
6.11 | Object, Class, and Interface Utilities
6.12 | Surrogates

On this page:

equal<%>

top ← prev up next →

#### 6.8`` Object Equality and Hashing

By default, objects that are instances of different classes or that are instances of a non-transparent class are equal? only if they are eq?. Like transparent structures, two objects that are instances of the same transparent class (i.e., every superclass of the class has #f as its inspector) are equal? when their field values are equal?.

To customize the way that a class instance is compared to other instances by equal?, implement the equal<%> interface.

interface equal<%> : interface?

The equal<%> interface includes three methods, which are analogous to the functions provided for a structure type with prop:equal+hash:

- equal-to? — Takes two arguments. The first argument is an object that is an instance of the same class (or a subclass that does not re-declare its implementation of equal<%>) and that is being compared to the target object. The second argument is an equal?-like procedure of two arguments that should be used for recursive equality testing. The result should be a true value if the object and the first argument of the method are equal, #f otherwise.

- equal-hash-code-of — Takes one argument, which is a procedure of one argument that should be used for recursive hash-code computation. The result should be an exact integer representing the target object’s hash code.

- equal-secondary-hash-code-of — Takes one argument, which is a procedure of one argument that should be used for recursive hash-code computation. The result should be an exact integer representing the target object’s secondary hash code.

The equal<%> interface is unusual in that declaring the implementation of the interface is different from inheriting the interface. Two objects can be equal only if they are instances of classes whose most specific ancestor to explicitly implement equal<%> is the same ancestor.
See prop:equal+hash for more information on equality comparisons and hash codes. The equal<%> interface is implemented with interface* and prop:equal+hash.

Example:

> #lang racket
> ;; Case insensitive words:
> (define ci-word%
> (class* object% (equal<%>)
> ;; Initialization
> (init-field word)
> (super-new)
> ;; We define equality to ignore case:
> (define/public (equal-to? other recur)
> (string-ci=? word (get-field word other)))
> ;; The hash codes need to be insensitive to casing as well.
> ;; We'll just downcase the word and get its hash code.
> (define/public (equal-hash-code-of hash-code)
> (hash-code (string-downcase word)))
> (define/public (equal-secondary-hash-code-of hash-code)
> (hash-code (string-downcase word)))))
> ;; We can create a hash with a single word:
> (define h (make-hash))
> (hash-set! h (new ci-word% [word "inconceivable!"]) 'value)
> ;; Lookup into the hash should be case-insensitive, so that
> ;; both of these should return 'value.
> (hash-ref h (new ci-word% [word "inconceivable!"]))
> (hash-ref h (new ci-word% [word "INCONCEIVABLE!"]))
> ;; Comparison fails if we use a non-ci-word%:
> (hash-ref h "inconceivable!" 'i-dont-think-it-means-what-you-think-it-means)

top ← prev up next →