[racket] TR: struct: #:prefab option

From: Ray Racine (ray.racine at gmail.com)
Date: Mon May 6 13:45:05 EDT 2013

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>

Posted on the users mailing list.