Please, I prefer the term dinosaur. :-)
Here's defresource from CLIM: - https://github.com/franzinc/clim2/blob/master/clim/defresource.lisp
On Fri, Aug 26, 2016 at 9:26 AM, David McClain <dbm@refined-audiometrics.com
wrote:
I knew there would be some old-dog out there that had a few tricks up his sleeve. Sadly, I am post-Genera generation. Thanks for chiming in there Scott. Gives me a lot to chew on.
- DM
On Aug 26, 2016, at 06:17, Scott McKay swmckay@gmail.com wrote:
From my perspective, there are two orthogonal things going on here:
- The idea of a "resource" with a well-defined protocol for allocation,
initialization, deinitialization, and deallocation. Genera (and CLIM) had macrology for this: defresource to define a resource, using-resource to use it in a "safe" way such that all those things happened in order. 2. Having let behave like using-resource.
It would be perfectly simple to write a let macro that shadows cl:let, which tracks allocation/initialization of resources, evaluates the body, and then calls the deinitializer/deallocator. How you implement "resources" is up to you. :-)
On Fri, Aug 26, 2016 at 7:52 AM, David McClain < dbm@refined-audiometrics.com> wrote:
Yes, finalizers can sometimes work. I have those in place. But they are tricky. Suppose I hand off a local channel to another thread to utilize of communication between us. Now there are two copies of that channel pointer. So when my local use goes out of scope, there is still one copy in use, by that thread. And that thread is likely just hanging, waiting for something to come across that channel, that never will, since it just went out of scope from the sending side. Hence GC will never have the opportunity to finalize.
Instead, you have to invent contorted references to the channel that can be neutralized by the sender when it goes out of scope. And I say contorted because these references have to be complex enough that the compiler won’t perform some stack optimization and produce an inadvertent secondary reference.
So, for example, it isn’t sufficient to make a reference to a channel as (list ch) / (car ch). That seems to become unwrapped at the receiver side by things like handler-case, ignore-errors. Rather you have to use a functional closure like (lambda () ch) / funcall. And now we’ve lost the symmetry of use on each side of the channel.
Not only that, but now we have to understand Lisp implementation details that we never needed to know before. And so we likely aren’t semantically portable.
Secondly, as you mentioned, not all Lisp support finalization, or not very well. Lispworks does fine, but I find SBCL particularly weak in that you only get told about an object being scavenged after it has already happened. Hence you have to keep a display array and use indirect references in SBCL.
What I recall from C++ world is that the automatic destructor calls at scope exit only happen on stack allocated objects, not pointers. Makes sense, since pointers allow for the possibility of alias pointers all over the place. Well, that’s exactly the situation we have in most Lisps too. In fact there can be no such thing as a stack allocated object, even if it really is allocated on the stack.
So then we have to invent reference counting to be sure we don’t destroy a shared object pointer too soon.
What I’m asking for really isn’t safe in Lisp. The best we can do, it seems, is what David proposes with his Scope macro, or my WITH- / UNWIND-PROTECT.
- DM
On Aug 25, 2016, at 22:42, Nick Levine nick@nicklevine.org wrote:
Would finalisers do the trick?
Not part of the language itself, but many implementations support them.
Various caveats apply. In particular you cannot guarantee when (or I
guess whether) any particular resource will be finalised; only that the GC will get around to most resources in the fullness of time. So this solution might not meet your needs.
- nick