[ tl;dr See the newly added struct-guard/c ]
I agree this is a problem (and a pernicious one!).
Thinking about it from the contract system design point of view, the
way serializable struct work this looks a lot like the situation where
the module author has (separately) exported the constructor without a
contract. And that's clearly a use-case we need to support (assuming
we believe in the idea of boundaries and having more than one
contract, etc; things that are pretty fundamental to the current
design).
Thinking about it from the serialization point of view, there is no
place where the programmer can communicate with the serialization
library to say "this use of deserialize (inside the module) is
different from that one (outside the module) so please check contracts
here instead of there".
As far as I can tell, the only way to rationalize these is to have a
single form that puts the contracts on a boundary with the
serialization information at the same place, meaning that all uses of
deserialize (and all uses of the selectors, etc.) have the contract
checks on them. This is, I believe, the solution that Matthew
suggested (as linked from the message below). There would probably
need to be some help to make that smoother if we wanted to continue in
that specific direction, tho.
Instead (thanks to discussion with Matthew and Christos), I've added
struct-guard/c. It accepts contracts and returns a procedure suitable
for use as the #:guard argument to serializable-struct and struct (and
friends) that checks the contracts when the constructor is called.
Note that this approach does not (cannot) check contracts when a
struct is mutated. So be sure to use it only when you have an
immutable struct or a struct whose mutable fields can safely be
`any/c`.
Here's an example of use, based on Philip's below.
#lang racket/base
(module server racket/base
(require racket/serialize
racket/contract)
(provide (struct-out boxed-set))
(serializable-struct boxed-set (v)
#:transparent
#:guard (struct-guard/c integer?)))
(require racket/serialize
racket/list
(submod "." server))
(define (corrupt-serialized s)
(list-set s 6 '(0 "not a set")))
(define (make-empty-boxed-set/bad)
(deserialize
(corrupt-serialized
(serialize (boxed-set 1)))))
(boxed-set-v (make-empty-boxed-set/bad))
Robby
> --
> You received this message because you are subscribed to the Google Groups "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
racket-users...@googlegroups.com.
> For more options, visit
https://groups.google.com/d/optout.