Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by

Finalize is called for reified objects even when they are still reachable. It gets called second time at proper time.

`
user=> (def x (reify Object (finalize [o] (println "OH MY!"))))

'user/x

user=> (System/gc)
nil
OH MY!
user=> x

<user$reify1496 user$reify1496@53fb35af>

user=> (System/gc)
nil
user=> (def x nil)

'user/x

user=> (System/gc)
nilOH MY!
`

Deftype seems to work fine

`
user=> (deftype T [] Object (finalize [o] (println "great success")))
user.T
user=> (def y (->T))

'user/y

user=> (System/gc)
nil
user=> (def y nil)

'user/y

user=> (System/gc)
great success
`

6 Answers

0 votes
by

Comment made by: alexmiller

Just a note: the calls to System/gc don't necessarily cause finalizers to run on the first try - sometimes it took more than one for that to succeed for me. You'd think System/runFinalizers would do it but I had no luck at all with that.

0 votes
by

Comment made by: gfredericks

{{reify}} actually creates two objects -- the first is created by * }, and then {{reify}} immediately calls {{with-meta}} on it, creating a copy.

The docstring sort of describes this behavior: "reify always implements clojure.lang.IObj and transfers meta data of the form to the created object."

0 votes
by

Comment made by: wagjo

Oh, so finalizer is a no-no in reify. Should be mentioned in docs IMO.

0 votes
by

Comment made by: gfredericks

Just for fun you could do something tricksy like:

`
^::second-object
(reify Object
(finalize [self]

(when (::second-object (meta self))
  ...)))

`

(have not actually run this)

0 votes
by

Comment made by: gfredericks

It looks like the class generated by {{reify}} always has a constructor that takes a metadata argument, so it doesn't seem out of the question to eliminate the extra object altogether.

I'll try to keep digging on this.

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-1347 (reported by wagjo)
...