lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Am 22.05.2014 08:36 schröbte Tim Hill:

On May 21, 2014, at 11:29 PM, Philipp Janda <siffiejoe@gmx.net> wrote:

Yes, that's exactly what I meant with degradation of lifetime granularity. On Lua 5.2 a weak-valued field keeps the reference until the finalizer has run which is what you need, it's just Lua 5.1 that is underspecified in this regard ...

It’s then a simple matter to have A call B’s finalizer before it does
its own finalization, ensuring B is always done first, assuming of
course that’s B’s finalizer is idempotent. This pattern will always
work regardless of the behavior of the GC. This can even be
generalized by having A maintain a table of references to many B’s.

So in the case of my `SDL_Quit` finalizer, it keeps all other SDL objects alive until `lua_close` ...

Possibly .. but that depends on how you design object lifetime for
your app.. If you want B to be collected independently of A then
clearly the A->B reference needs to be weak. I think the point to my
mind is that, with the correct combination of strong and weak
references, and idempotency, you can create whatever object lifetimes
you need without relying on the ordering of finalizers by the GC.

With weak back references you get the problems I already mentioned two posts ago. Anyways, we obviously need some way to manage lifetime dependencies, and the current approach is easy and naturally fits the most common case where one object depends on another for its entire lifetime.

And even if the GC *does* guarantee the ordering, you are then
dependent on objects being created in the correct order to ensure
they are deleted in the correct order .. that can be a tricky thing
to maintain and debug, compared to a design that always does the
“right thing” at shutdown.

Or it can be very easy: E.g. require an argument of type A in your B constructor and you know for sure that the A object was created before the B object. For APR and SDL this is also exactly how the C API looks like. Eric's case is quite complicated though ...


Another point, of course, is that using sequences like “objectX =
nil; collectgarbage()” can be inefficient compared to explicit
Dispose() patterns (GC’s have significant overhead). In this model,
the finalizer is just the “last chance” to dispose of the object.

As soon as you have garbage collection and lifetime dependencies, manual disposal doesn't work that well anymore: E.g. if I cleared an APR memory pool (which is possible in the C API), I would break all userdata objects that were created using this memory pool. This is also the reason why exposing something like `SDL_Quit` to Lua is dangerous. Manual management is only possible at the leaf nodes of such a lifetime dependency graph (e.g. I can manually close/delete an APR file object without problems even if it depends on a memory pool).


—Tim


Philipp