That's what I think. The more contracted our values get in Racket programs, the less we can trust `register-finalizer` if it doesn't change.

Currently, `register-finalizer` tends to be used right after allocation, when objects don't usually have contracts yet. It doesn't have to be, though.

Neil ⊥

On 08/16/2014 10:46 AM, Sam Tobin-Hochstadt wrote:
That's clearly the right solution for this particular bug, but it does
seem like there's a more general problem here.

Sam

On Sat, Aug 16, 2014 at 10:40 AM, Robby Findler
<ro...@eecs.northwestern.edu> wrote:
Seems simplest to be to have typed racket know to trust register finalizer
and thus avoid wrapping it with a contract.

Robby


On Saturday, August 16, 2014, Neil Toronto <neil.toro...@gmail.com> wrote:

Short version: the contract system doesn't allow `register-finalizer` to
be used in Typed Racket.

Long version: consider the following Typed Racket program, in which
instances of `os-resource-wrapper` represent an operating system resource
`os-resource`, which itself is just a counter. It attempts to register a
finalizer for allocated wrappers, which decrements the counter.


#lang typed/racket

(require/typed
  ffi/unsafe
  [register-finalizer  (All (A) (-> A (-> A Any) Void))])

(: os-resource Integer)
(define os-resource 0)

(struct os-resource-wrapper ())

(: alloc-os-resource (-> os-resource-wrapper))
(define (alloc-os-resource)
   (set! os-resource (add1 os-resource))
   (define w (os-resource-wrapper))
   (register-finalizer w (λ (w) (set! os-resource (sub1 os-resource))))
   w)

(define w (alloc-os-resource))
(printf "os-resource = ~v~n" os-resource)
(collect-garbage)
(sleep 1)  ; give finalizers a chance to run
(printf "os-resource = ~v~n" os-resource)


I get this output:

   os-resource = 1
   os-resource = 0

The finalizer is being run while the program still has a pointer to the
wrapper object. I think it's because the wrapper object is being
impersonated when it's sent across the contract barrier, and the
*impersonator* is getting the finalizer. (Or it's a chaperone, or an
impostor, or a charlatan, or whatever. Let's go with impersonator.)

In my specific case, the OS resources are OpenGL objects; e.g. vertex
object arrays. The call to `register-finalizer` *must* be in Typed Racket
code because the wrapper contains an (Instance GL-Context<%>), which can't
have a contract put on it, so it can't pass from untyped to typed code.

Is there any reason for `register-finalizer` to behave this way? Does it
ever make sense to register a finalizer on an impersonator?

Neil ⊥
_________________________
  Racket Developers list:
  http://lists.racket-lang.org/dev


_________________________
   Racket Developers list:
   http://lists.racket-lang.org/dev


_________________________
 Racket Developers list:
 http://lists.racket-lang.org/dev

Reply via email to