|
First of all, thanks for your answers, Roberto. Am 23.11.2015 um 18:25 schröbte Roberto Ierusalimschy:
The chief difficulty is that an object referenced by such a variable can be assigned to another variable (stored in a table, captured in a closure), and vice versa. And, if that is not prevented, then the other variable may end up holding a reference to a finalized object. Today's resurrection could also result in that, but today resurrection is fully controlled by the finalizer and hence its library's writer; changing that will make a lot of existing libraries invalid.I think it is a good practice to allow objects to be "finalized" multiple times (that is, to allow their __gc metamethod to be called multiple times) and also to allow references to finalized objects with sensible behavior. First, if the library does not protect metatables, any code can get the __gc metamethod and call it explicitly.
IMHO, protecting the metatable is a good idea anyway so that no-one removes the `__gc` metamethod and you run out of resources somewhere else.
Second, it is a good practice (well, I think it is) to provide an explicit way to "close" an object that needs finalization. The io library, for instance, does that.
It's easy for the io library, because it stores pointers. Downside is that the garbage collector isn't aware of the extra memory, and memory fragmentation could be higher since there are multiple allocations for each userdata now. For every non-pointer userdata you'd have to add an extra field to indicate the state of finalization. But now every (meta-)method has to check that the userdata is still valid, and most Lua code that uses those (meta-)methods has to check again unless it is ok with a simple getter/setter throwing an error. Also there are cases where explicitly "closing" an object is unsafe, e.g. if another object holds a pointer to that object. You can ensure the correct `__gc` order by storing references in the appropriate uservalue tables, but invalidating dependent objects is harder -- especially if the dependencies might change at runtime. Concrete examples from the last three libraries I created bindings for are renderers and textures in libSDL, memory pools and any other APR object in the Apache Portable Runtime library, and Fl_Input_Choice and its Fl_Input and Fl_Menu_Button subwidgets in FLTK.
Maybe the hypothetical "block" variable should only call `__gc` if the metatable is not protected (hoping that the author has taken proper care). Alternatively, a new (meta-)method could be introduced.
-- Roberto
Philipp