[racket] Destructors in Racket

From: Evgeny Odegov (oev-racket at sibmail.com)
Date: Sat Aug 2 11:47:32 EDT 2014

In the example, the value is box and triggering occurs almost 
immediately after set!.
But in case of another kind of value, triggering doesn't occur or take 
much longer.
Why? (Or maybe I do something wrong?)

> 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
> ____________________
>    Racket Users list:
>    http://lists.racket-lang.org/users


Posted on the users mailing list.