[racket] struct equality?

From: Neil Toronto (neil.toronto at gmail.com)
Date: Tue Jul 6 12:59:17 EDT 2010

Todd O'Bryan wrote:
> OK, this is harder than I thought. The struct is defined at the top
> level, so under what conditions might it be re-defined?
> 
> Also, will an accessor of the form struct-name-field work with any
> struct of name struct-name, or does it only work with structs that are
> in the same scope?

The only time I know of that equivalent #:transparent structs don't 
compare equal is when they're defined in different phases. If there's a 
struct type called A that you require both normally and for-syntax, the 
normal make-A will create a struct of a different type than the 
for-syntax make-A.

It's hard to observe the difference by accident, so seeing it is 
surprising. Here's a demo. In the following, module 'a makes a struct 
type A and provides it. Module 'b requires it normally (phase 0) and 
for-syntax (phase 1), and creates A-type values in both phases. Then an 
evil macro uses syntax quasiquote/unquote to make the phase 1 value 
visible in phase 0:

 > (module a racket
     (define-struct A (value) #:transparent)
     (provide (struct-out A)))
 > (module b racket
     (require 'a (for-syntax 'a))  ; require 'a in phase 0 and phase 1
     (define a1 (make-A 1))             ; ph-0 value, ph-0 constructor
     (define-for-syntax a2 (make-A 1))  ; ph-1 value, ph-1 constructor
     ; get a2 into phase 0 as a quoted struct value
     (define-syntax (get-a2 stx)
       (syntax-case stx ()
         [(_)  #`#,a2]))
     (define a2 (get-a2))  ; ph-0 value made by ph-1 constructor
     (provide a1 a2))
 > (require 'a 'b)  ; require 'a and 'b in phase 0
 > (equal? a1 a2)
#f
 > (A-value a1)  ; can use phase 0 A-value to get value from a1
1
 > (A-value a2)  ; CANNOT use phase 0 A-value to get value from a2
A-value: expects args of type <struct:A>; given instance of a different 
<struct:A>


If it helps, you can think of the first three lines in module 'b as

   (require (prefix-in phase-0- 'a)
            (prefix-in phase-1- (for-syntax 'a)))
   (define a1 (phase-0-make-A 1))
   (define-for-syntax a2 (phase-1-make-A 1))


FWIW, I have no idea why structs are treated specially like this. It 
works fine with primitive types like strings:

#lang racket
(define a1 "hello")
(define-for-syntax a2 "hello")
(define-syntax (get-a2 stx)
   (syntax-case stx ()
     [(_)  #`#,a2]))

 > (equal? a1 (get-a2))
#t


Seems it would be useful occasionally to not worry about the phase 
distinction. Hope this helps!

Neil T



Posted on the users mailing list.