[racket] TR: struct: #:prefab option
FWIW,
Here is what I've been doing in TR with regard to #:prefab struct: as a
mechanism for ser/de-ser. Notice the cast to the struct: type after
deserialization from a string. Of course the #:prefab struct: definition
must be in both client and server code and the definitions in sync.
#lang typed/racket/base
(provide
deserialize-struct-from-string
serialize-struct-to-string)
;; Open question here on what is best approach for serialization of struct:
lot's of APIs in R.
;; For now simple. This assumes the structure is prefab or equivalent.
(define-syntax deserialize-struct-from-string
(syntax-rules ()
((_ str type)
(let ((sin (open-input-string str)))
(let ((s (cast (read sin) type)))
(close-input-port sin)
s)))))
(define-syntax serialize-struct-to-string
(syntax-rules ()
((_ struc)
(let ((outp (open-output-string)))
(write struc outp)
(close-output-port outp)
(get-output-string outp)))))
On Mon, May 6, 2013 at 1:39 PM, Asumu Takikawa <asumu at ccs.neu.edu> wrote:
> On 2013-05-06 08:46:04 -0700, Eric Dobson wrote:
> > Couldn't this be solved by protecting the struct on export?
>
> I'm not sure this is sufficient. Consider the following code:
>
> #lang racket/load
>
> (module foo racket
> (struct foo ([f #:mutable]) #:prefab)
> (define y (foo values))
> (define (mutater) (set-foo-f! y (λ (x) (string->number x))))
> (provide y mutater))
>
> (module bar typed/racket
> (struct: foo ([f : (Float -> Float)]) #:mutable #:prefab)
> (require/typed 'foo
> [y foo]
> [mutater (-> Void)])
> (mutater)
> ((foo-f y) 5.3))
>
> The use of mutation lets you sneak values that don't match the type.
> Even if you require the struct instance with `struct/dc` and apply an
> impersonator-based contract, you can't prevent the un-impersonated
> access on the `foo` side.
>
> This actually looks like it's a problem even without #:prefab structs:
>
> #lang racket/load
>
> (module foo racket
> (struct foo ([f #:mutable]))
> (define y (foo values))
> (define (mutater) (set-foo-f! y (λ (x) (string->number x))))
> (provide y (struct-out foo) mutater))
>
> (module bar typed/racket
> (require/typed 'foo
> [#:struct foo ([f : (Float -> Float)])]
> [y foo]
> [mutater (-> Void)])
> (mutater)
> ((foo-f y) 5.3))
>
> Another thing to be careful of is struct inheritance. For example:
>
> #lang racket/load
>
> (module foo typed/racket
> (struct: foo ([f : (Float -> Float)]) #:prefab)
> (struct: foo2 foo ([g : (Float -> Float)]) #:prefab)
> (define x (ann (foo2 (λ (x) (* x 5.3))
> (λ (x) (* x 5.3)))
> foo))
> ;; Note that this is a type error
> ;(foo2-g x)
> (provide x))
>
> (module bar racket
> (require 'foo)
> (struct foo (f) #:prefab)
> (struct foo2 foo (g) #:prefab)
> ((foo2-g x) "foo"))
>
> In this case, `foo2` inherits from `foo` and so you can upcast an
> instance of `foo2` to `foo`. But then you forget a field, and if the
> type->contract translation isn't smart, then you may fail to protect all
> the fields (that an untyped client can now guess and misuse).
>
> Cheers,
> Asumu
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130506/3ffc0699/attachment-0001.html>