schemeracket

What is the difference between `some-struct?` and `#<some-struct>` in Racket?


I have a struct

(struct client-sock-addr (host port))

I have a toText function

(define (toText.v1 addr)
  (string->chunked-string (format "<client-sock-addr ~a ~a>" (client-sock-addr-host addr) (client-sock-addr-port addr))))

When this code is executed, I get a contract violation error:

client-sock-addr-host: contract violation
  expected: client-sock-addr?
  given: #<client-sock-addr>
  context...:
   client-sock-addr-host

I am relatively new to Racket, and I have been reading over the docs, and I can't for the life of me figure out what #<...> means. It looks like it's what the REPL spits out when you construct an instance of the type, but then why does the function fail saying it's not of type client-sock-addr??

Thank you.


Solution

  • Unless it's a prefab structure, two calls to struct will create two different incompatible structure types, even if they have the same name and fields and printed representation. You can't pass a value created by the first struct's constructor to an accessor function of the second struct, which appears to be what's happening here.

    A demonstration:

    #lang racket/base
    
    (module a racket/base
      (provide x y)
      (struct foo (bar))
      (struct prefab-foo (bar) #:prefab)
      (define x (foo 1))
      (define y (prefab-foo 1)))
    (require 'a)
    
    (struct foo (bar))
    (struct prefab-foo (bar) #:prefab)
    (foo? x) ; #f
    (prefab-foo? y); # t
    

    #<client-sock-addr> is an example of an unreadable value; the default printed representation of an opaque struct (one that's not transparent or prefab) that doesn't have a custom write method.

    (In other words, it is how Racket displays an object it doesn’t know how to display to you.)