1

i'd like to perform some actions on a particular entity after there are no longer any references to it, but before the garbage collector wipes its data out. i'm using this for an experiment with more "purely functional" gui abstractions. here is what i'd like to do:

(let [window (make-window width height)] ; A
  (various-actions window)
  (let [window (resize window new-width new-height)] ; B
    (more-actions window))
  (and-more-actions window)) ; C

at A a window instance is created with a width and height. eventually i want to change the window at B. the code treats this like an immutable action, but underneath the window will simply change to reflect the changes. actions performed on the A scope's window while the B scope's window exists (in case of multithreading) would not be allowed in some manner.

at C after we finish doing stuff at B and leave that let scope, the B window object will be unreferenced and garbage collected. but i want to signal the underlying window mechanism that it should roll back the B changes now, and accept A scope activity again. thus action at C will be as though B effects didn't happen.

as well, if the top level A window is no longer referenced, it should destruct itself in whatever manner before garbage collection.

i could possibly manage this by having make-window modify a global state which registers window references, but i'm not sure how to detect the point at which the B scope reference is lost. how can i check the references to a piece of data? or is there some other way to address this problem?

i realize this is a somewhat convoluted set-up, but i want to find a way to reconcile the statefulness of gui programming and make it appear to be as pure as possible.

xen
  • 133
  • 6
  • `(let [window (make-window width height)] (let [different-window (resize window new-width new-height)] (more-actions window))` –  Jun 23 '14 at 06:18
  • @delnan This is not different in any meaningful way from OP's existing code. The compiler doesn't care whether two different variables have the same textual name or not; the two `window` variables in his example are as separate as in yours. – amalloy Jun 23 '14 at 07:36
  • @amalloy One of us need to read again more carefully. Here's my understanding: `resize` mutates the Window object, but OP wants to maintain the illusion of purity, hence *shadows* the sole other binding (which is supposed to refer to an immutable object). My code snippet does not shadow, hence can use the outer reference, and thereby exposing the mutation using perfectly ordinary, valid code. I could also use a more complex example with aliasing from collections or the like but I chose to stick closely to OP's code structure. –  Jun 23 '14 at 07:46
  • @delnan your concern isn't invalid, but my plan for this scenario is that while different-window is "alive", actions on window would be "invalid" in some way. i think transients are capable of this, so i'd probably use a similar mechanism. – xen Jun 23 '14 at 11:08

1 Answers1

0

This is not the way to build a correct program. A correctly-written program cannot assume that garbage collection is ever run, and certainly it won't run as instantaneously as you'd like in order to make a UI decision based on it.

It's not at all clear from your problem description what you actually want to do, but tying it to garbage collection is sure to be the wrong way to do it. Perhaps you could add some code after leaving B that will do whatever it is that you want.

amalloy
  • 89,153
  • 8
  • 140
  • 205
  • you are correct, i shouldn't rely on the garbage collector specifically. what i want is to perform actions when the amount of "references" to a var or such reduces (at the end of a let/binding scope). what i actually want to do is model the mutable state of a gui application as though it were less mutable, and apply changes to it only when immutable wrappers are created and "destroyed". destroyed doesn't need to mean garbage collected, it just needs to mean its scope has been left and it's not referenced any longer. – xen Jun 23 '14 at 11:12