Custom equality predicate - in struct/gen:equal+hash or extra function?

Assuming you have a struct

(struct foo (a b c)
  #:transparent)

and you want a custom equality predicate. For example, two foo instances should be equal? if their corresponding a and b fields are equal?, regardless of the c field value.

One way would be to define the gen:equal+hash interface. Another way would be to define a foo=? procedure (following the pattern of string=? or char=?).

I guess defining the generic interface is preferable because

  • The equal?comparison is used if you want to compare foo instances in containers. For example, you could compare lists like (list (foo 1 2 3) (foo 4 5 6)) with equal?, even recursively.
  • equal?-based hashes automatically use the custom interface.

On the other hand, defining just a foo=? function has other advantages:

  • It's simpler.
  • It makes clear what you want to compare, even without looking at the surrounding code.

I've also seen both approaches combined, i.e. equal? support already exists, but there's also a v=? function that returns (equal? v1 v2). Example: boolean=?.

I can also imagine the case where the values you want to compare aren't structs. At first sight, you can't use the generic interface then. However, you could always wrap the value in a single-field struct.

What do you think? When would you use one or the other of the two approaches? Have you run into bugs or other problems from using one of the approaches, and why?

I think it's better to always support the first method so it cooperates with the rest of Racket. And perhaps also add the second method too to get an error in case there is a bug and you expected to compare two instances of an struct and you are actually comparing a struct and something else, for example you used cdr instead of cadr and get (list (foo 1 2 3)) instead of (foo 1 2 3).

The only reason to use only the second method is when the comparison criteria is not clear, like bound-identifier=?, free-identifier=?, module-or-top-identifier=? and a few similar versions.

1 Like