Definition: | object o = delete_routine(object o, integer rid) |
Description: | Associate a cleanup routine with some data, to be invoked when it gets destroyed. |
Comments: |
When the reference count on a data object drops to zero it is automatically garbage collected. This routine allows additional processing
to occur at the point when that happens, which may include freeing some allocated memory, closing a file, releasing some other resource,
or removing indexes that point to an item. It is also possible to explicitly invoke delete() on remaining objects
ahead of their eventual destruction, to force any such additional processing to occur immediately, or in a specific order.
The routine specified by rid should be a procedure that takes a single parameter, being the object to be cleaned up. It is usually the case that you would apply delete_routine() to individual table elements rather than a whole table. The data passed to delete_routine should whenever possible be "final". Appending, prepending, or replacing elements of data after delete_routine has been applied may or may not invoke the cleanup routine as you might hope (invocation depends mainly on the triggering of an internal clone operation, perhaps because of insufficient space or multiple reference counts). An error occurs if a delete_routine has already been set. This is inconsistent with OpenEuphoria, which allows daisy-chains of cleanup routines, however my argument is that it is better to prevent routines such as unlink (below) from being invoked twice, than it is to permit the added but questionable extra flexibility. Besides there is nothing to prevent the data from containing a list of routine_ids that the one associated cleanup routine can invoke in turn, and if you put unlink in that list twice it is your problem not mine, but at least it is trivial to scan such a list, something you would struggle to do with multiple hidden internal associations. An error also occurs when an attempt is made to apply a routine_id to a constant (with the exception of integer constants, because the run-time simply cannot determine whether an integer value such as 4 is originally from open() or MB_YESNO - however I reserve the right (albeit with no actual intention or schedule) to add compile-time errors for the latter at some future date). Obviously invoking, say, routine_id("test",rXXX) is utterly pointless - the constant "test" is never going to be destroyed, and hence rXXX would never be invoked. This is also inconsistent with OpenEuphoria. Should an integer be passed as the first parameter, it is promoted to atom. This is required for memory allocations, as some may fall below the magic #3FFFFFFF boundary. Note this may affect some comparison operations, as internally the run-time (eg builtins\VM\pJcc.e) assumes that integers and floats are never equal. It is legal to invoke delete_routine(<object>,0). This has the effect of removing any association without invoking it. It has the further effect of resetting the pHeap link, see technicalia. The routine_id is validated to ensure it is not -1, but only when the first parameter is non-integer. Some memory allocation routines offer default delete_routines as part of automatic memory management. |
Example: |
sequence list = {} intlisthead = 0 procedure unlink(sequence item) if item[PREV]=0 then listhead = item[NEXT] else list[item[PREV]][NEXT] = item[NEXT] end if if item[NEXT]!=0 then list[item[NEXT]][PREV] = item[PREV] end if close(item[FILEHANDLE]) free(item[MEMPTR]) end procedure procedure add(sequence item) item[PREV] = 0 item[NEXT] = listhead list = append(list,delete_routine(item,routine_id("unlink"))) if listhead!=0 then item[listhead][PREV] = length(list) end if listhead = length(list) end procedure |
See Also: | delete, allocate |
