On Sat, Jul 20, 2013 at 12:25 AM, William ML Leslie <
[email protected]> wrote:

> On 20 July 2013 07:51, Jonathan S. Shapiro <[email protected]> wrote:
> > On Thu, Jul 18, 2013 at 8:09 PM, William ML Leslie
> > <[email protected]> wrote:
> >>
> >> However, if disposables cannot escape a task anyway, then disposables
> >> are task-local, so you already know (or, already can track) what needs
> >> to be disposed of at task exit.
> >
> >
> > Except, as I noted, that disposables can cross task boundaries and become
> > shared in real systems.
>
> Yes, capability theory has taught us to pass around file handles
> rather than file names and URLs, and naive implementations of this
> mean that resources are not task local.  But I was actually trying to
> introduce a strawman, because even if they were, refcounting doesn't
> solve the problem of prompt finalisation significantly better than any
> other mechanism.  Refcounting would tell you about the objects that
> would like finalisation just like finalising the task-local heap
> would.
>

Well done on the straw man - I fell for it briefly, and I'm certainly not
the only one who has done so in discussions like this. In fact I know of
some others... :-)

But I think we are once again talking about refcounting at different
layers, and refcounting *is* significantly better than finalization. If we
are talking about kernel-level resources (whether real or
runtime-simulated), we aren't talking about in-application-heap refcounts.
What we are talking about is counted references that are maintained by the
runtime or the kernel.* *Further, we know that no cycles are possible for
these particular references, because the objects they "point" into a lower
layer of abstraction.

At that point it becomes a question of "simplest mechanism for the job",
and I think for this problem it's ref counting, not GC.


> >> In any case, for a large number of programs, there needs to be a way
> >> to specify finaliser order.
> >
> >
> > You do not and cannot get that guarantee out of any semantically sane
> > semantics of finalization. Finalizers, of necessity, execute in
> unspecified
> > order. If you need an order of disposition, you need to implement that in
> > the application. This is why the  .NET Dispose() pattern is so important.
>
> Sure they do.  In C++ you know that your destructor is run before
> those of your fields, you can usually be sure that most fields of the
> object you're destructing are still present (they may not be live, but
> they are usually still operational).  This means that object
> composition becomes a means of specifying finaliser order...


C++ destructors are not finalizers. C++ destructors are not guaranteed to
be run *at all* when references are lost. So no, you do *not* get an
ordering guarantee unless your code survives to explicitly destroy (tear
down) those objects that need destruction. The loss of that code and/or
those references is exactly the problem that finalization is attempting to
resolve.


> But for execution
> of a finaliser to make any sense, the objects that it operates on need
> to be usable, and they may not be if they have been finalised.
>

I agree that this is a problem, and you are hitting here on why finalizers
are so hard to use properly.

First, I think we need to acknowledge that in current programming languages
the only sane form of finalization is what you called weakref callbacks. By
the time those are called, the object being finalized is *gone*. There is
no way to trace any connection of any form (ordering or other) between the
objects whose weakref callbacks are being invoked.

The callback closures themselves may have references to objects that, in
their turn, will need finalization after the closure has been released.
This is why finalization on exit may require multiple calls to the "major
GC" function. You need to keep calling major-gc-and-finalize until there
are no more weakref callbacks to be invoked. But this process of
progressive release is the only sequencing guarantee you get in
finalization.

Non-escaping destructors would allow us a different approach, because those
can be run with a live object reference. In that situation you *can* run
structured finalization in the way you seem to be suggesting.

Personally, I think that weakref callbacks are a* *poor alternative to
non-escaping finalizers, but it would probably be a good idea if I write
down what I mean by a non-escaping finalizer. And it's likely to turn out
that I haven't quite got the right name for them.

> RAII works fine. If you mean what I suspect by "weakref callbacks", that's
> > not fine - the result is a system that is not GC-safe.
>
> Probably not, then!
>
> The GC keeps a weakly-keyed map[0], the value of which is a closure
> that will be called once the object is collected.  Because the object
> is already collected when the callback is invoked, the callback can't
> revive it.  Because the reference to the callback is not weak, it may
> reference any other resource that requires finalisation.
>

Yes. Sorry. I guessed incorrectly what you meant by "weakref finalization".
Given your description, it's clear that you are thinking of a semantically
sensible form of finalization. Indeed the only such mechanism that I know
about.


Jonathan
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to