A variant on Alexis' example lets you circumvent Typed Racket's protections:

#lang racket

(module typed typed/racket
  (provide wrapper use)
  (struct wrapper ([v : Integer]))
  (: use (-> wrapper Integer))
  (define (use w)
    (add1 (wrapper-v w))))

(require racket/runtime-path)

(define-runtime-module-path typed
  (submod "." typed))

(define-values {wrapper use}
  (parameterize ([current-inspector (make-inspector)])
    (values (dynamic-require typed 'wrapper)
            (dynamic-require typed 'use))))

(define unchecked-wrapper
  (let-values ([(info skipped?)
                (struct-info (wrapper 0))])
    (struct-type-make-constructor info)))

(use (unchecked-wrapper 'nonsense))

Maybe this is well-known to everyone who's thought about it before, but I
hadn't. Though I guess, while I don't think about inspectors very often, I
think of them as a way for one module to put others under its control, in
which case maybe the module with the more powerful inspector *should* be
able to break subordinate modules' invariants.

-Philip


On Mon, Nov 5, 2018 at 9:01 PM Ryan Culpepper <ry...@ccs.neu.edu> wrote:

> On 11/5/18 5:26 PM, Alexis King wrote:
> > To my knowledge, there are two main techniques for creating unique
> values in Racket: `gensym` and structure type generativity. The former
> seems to be bulletproof — a value created with `gensym` will never be
> `equal?` to anything except itself – but the latter isn’t. Using reflective
> operations, it’s possible to circumvent the encapsulation afforded by the
> module system.
> >
> > To provide an example, `racket/contract` exports a value called
> `the-unsupplied-arg`, which is created using the usual structure type
> generativity trick:
> >
> >     (define-struct the-unsupplied-arg ())
> >     (define the-unsupplied-arg (make-the-unsupplied-arg))
> >     (provide the-unsupplied-arg)
> >
> > The constructor is not exported, and this value is intended to be
> unique. However, if we can arrange for the contract library to be loaded on
> our terms, we can thwart this encapsulation by supplying it with a weaker
> inspector:
> >
> >     #lang racket/base
> >
> >     (define the-unsupplied-arg
> >       (parameterize ([current-inspector (make-inspector)])
> >         (dynamic-require 'racket/contract 'the-unsupplied-arg)))
> >
> >     (define-values [info skipped?] (struct-info the-unsupplied-arg))
> >
> >     (define another-unsupplied-arg ((struct-type-make-constructor info)))
> >
> >     (equal? the-unsupplied-arg another-unsupplied-arg) ; => #t
> >     (eq? the-unsupplied-arg another-unsupplied-arg)    ; => #f
> >
> > Perhaps this isn’t the end of the world, as after all, we can’t do
> anything especially nefarious with this value, and we wouldn’t be able to
> do it in the first place if we didn’t have complete control of the
> inspector hierarchy. Still, it seems a little unsatisfying.
> >
> > So, my question: is there any way to create a structure type for which
> there can truly ever only be one instance? If not, is there a fundamental
> reason why not?
>
> You could use a chaperone to prohibit `struct-info`:
>
>    (define the-unsupplied-arg
>      (chaperone-struct (make-the-unsupplied-arg)
>                        struct:unsupplied-arg
>                        struct-info (lambda _ (error "not allowed"))))
>
> Ryan
>
> --
> 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+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to