[racket] Destructors in Racket

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Sat Aug 2 08:38:08 EDT 2014

Probably you want to do something like this, I guess. It creates a
single thread that just waits until anything registered with
an-executor is garbage and then runs the executors. They will run
asynchronously, but perhaps that's okay for your usecase.

Robby

#lang racket
(define an-executor (make-will-executor))
(void
 (thread
  (λ ()
    (let loop ()
      (will-execute an-executor)
      (loop)))))

(define a-box (box #f))
(will-register an-executor
               a-box
               (λ (x) (printf "a-box is now garbage\n")))
(collect-garbage) (collect-garbage) (collect-garbage)
(printf "breaking the link\n")
(set! a-box #f)
(collect-garbage) (collect-garbage) (collect-garbage)

On Sat, Aug 2, 2014 at 7:31 AM, Roman Klochkov <kalimehtar at mail.ru> wrote:
> So I can write
>
> (define (make-obj stream)
>    (define res  (obj (open-output-file "out.dat")))
>    (define will (make-will-executor))
>    (will-register will res (lambda (x) (close-output-port (obj-file x))))
>    (thread (lambda () (let loop () (will-try-execute will) (sleep 1)
> (loop)))))
>
> to make my objects? Additional threads don't hinder performance, do they?
>
> Or should I somehow figure out if the thread is already running, don't run
> it and use common `will' for all objects?
>
> Sat, 2 Aug 2014 07:00:04 -0500 от Robby Findler
> <robby at eecs.northwestern.edu>:
>
> One way is to set up a separate thread to do that.
>
> The reason they are not called automatically is sometimes running the
> procedure passed to will-register needs to access some shared state
> and so your program must be allowed to be in control of the timing of
> the executor.
>
> In this case, it sounds like you can run the executor at any time, so
> just creating a thread to close the port inside my-obj should work
> fine.
>
> Robby
>
>
> On Sat, Aug 2, 2014 at 6:15 AM, Roman Klochkov <kalimehtar at mail.ru> wrote:
>> Then how?
>>
>> Suppose I have
>> (struct obj (file))
>> (define my-obj (obj (open-output-file "out.dat")))
>>
>> What I have to write to close the file, when my-obj will be GC'ed?
>>
>> I can write
>> (define will (make-will-executor))
>> (will-register will my-obj (lambda (x) (close-output-port (obj-file x))))
>>
>> But as far as I understand, it will not be called until `will-execute' or
>> `will-try-execute' will be manually called?
>>
>> Then how to call will-try-execute when GC is collecting my-obj?
>>
>>
>> Sat, 2 Aug 2014 11:57:32 +0100 от Matthew Flatt <mflatt at cs.utah.edu>:
>>
>> No, use the safe "will executors" API, instead.
>>
>> The unsafe finalizer API is for low-level, atomic finalization. Closing a
>> port can flush buffers and more, and it's not a good idea to do that in an
>> unsafe atomic context.
>>
>>> On Aug 2, 2014, at 11:12 AM, Roman Klochkov <kalimehtar at mail.ru> wrote:
>>>
>>> I have a structure, that has a filestream inside it. File have to be
>>> cosed, when the structure is not used anymore (so gargbage collected).
>>>
>>> Is the best way to do
>>> (require ffi/unsafe)
>>> (register-finalizer my-obj
>>> (lambda (x) (close-output-port (obj-file x))))
>>>
>>> ?
>>>
>>> It seems doing right thing, but why `ffi/unsafe'? Is it OK, when my
>>> program actually doesn't use FFI?
>>>
>>>
>>> --
>>> Roman Klochkov
>>> ____________________
>>> Racket Users list:
>>> http://lists.racket-lang.org/users
>>
>>
>>
>> --
>> Roman Klochkov
>>
>> ____________________
>> Racket Users list:
>> http://lists.racket-lang.org/users
>>
>
>
>
> --
> Roman Klochkov


Posted on the users mailing list.