[racket] Destructors in Racket

From: Gustavo Massaccesi (gustavo at oma.org.ar)
Date: Sun Aug 3 16:17:31 EDT 2014

The difference is that every time that (list 1 2 3) is executed, you
get a new different list. But with each '(1 2 3) you get every time
the same list. The '(1 2 3) is referenced from the "source code" so it
will not be collected. (A different copy of '(1 2 3) creates a
different list, but always the same list.)

Gustavo

;---
#lang racket/base
(define (get-list-123) (list 1 2 3))
(define (get-quote-123) '(1 2 3))
(define (get-quote-bis-123) '(1 2 3))

(eq? (get-list-123) (get-list-123)) ;==> #f
(eq? (get-quote-123) (get-quote-123))  ;==> #t
(eq? (get-list-123) (get-quote-123)) ;==> #f
(equal? (get-list-123) (get-quote-123))  ;==> #t
(eq? (get-quote-123) (get-quote-bis-123)) ;==> #f
(equal? (get-quote-123) (get-quote-bis-123))  ;==> #t
;---


On Sat, Aug 2, 2014 at 3:05 PM, Evgeny Odegov <oev-racket at sibmail.com> wrote:
> Well, it turns out that objects like #(1 2 3) or '(1 2 3)
> are not collected (optimizations?), but (vector 1 2 3) and
> (list 1 2 3) are collected normally. It so happens that I tried #(1 2 3)
> and '(1 2 3) first and came to the wrong conclusions :)
>
>
>
>
>>   > But in case of another kind of value
>>
>> What another kiind? Small numbers and some chars are not garbage
>> collected.
>>
>>
>> Sat, 02 Aug 2014 22:47:32 +0700 от Evgeny Odegov <oev-racket at sibmail.com>:
>>>
>>> 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
>>>
>>> ____________________
>>>    Racket Users list:
>>>     http://lists.racket-lang.org/users
>>>
>>
>
> ____________________
>  Racket Users list:
>  http://lists.racket-lang.org/users


Posted on the users mailing list.