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 <[email protected]> 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 [email protected].
> 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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to