Just to round this thread out, I'm attaching what *I* have come to use based on the above. It's not a lot of code, but it's working well for me. It's a small "Utils" library with the following functions:
1) o = Utils_CreateObject("basename")
This creates an internal object. The object visibility is set to false. The "basename" parameter is used to generate a unique name for the object. The created object names will be like "basename0", "basename1", etc. I originally didn't have that (using just a default base name), and it made it much more difficult to detect and resolve "object leaks". Now by providing good base names for your objects, you'll be able to scan the object list in the debugger and know what things are much more easily.
The object is marked as needing to be destroyed. You should call Utils_DestroyObject(o) when you're done with it.
2) o = Utils_CloneObject(prototype)
This creates an object as a clone of a prototype object. Note that the prototype parameter is a direct object reference, not an object name in quotes. The prototype is passed to Clone to generate a copy.
If the resulting object has a "create" script defined, then it will be executed on the new object after cloning.
The object is marked as needing to be destroyed. You should call Utils_DestroyObject(o) when you're done with it.
3) Utils_DestroyObject(o)
This function destroys an object "o" if "o" has been created by either Utils_CreateObject or Utils_CloneObject. If it was not created by either of those functions (and so marked internally), then nothing will happen. This means, among other things, that you can pass any object to this function, and only those objects that should be destroyed will be. (There are ways to allow other objecs to be destroyed with this function. I have not found a need for that yet.)
If the object has a "destroy" script, then the script will be executed before the object is destroyed. This allows the object to clean up anything it needs to (e.g. other objects).
4) Utils_DestroyObjectList(list)
This function is used to destroy a list of objects created by Utils_CreateObject and/or Utils_CloneObject. It simply removes each object from the list in turn and calls Utils_DestroyObject on it. You could, in theory, pass any object list into this. If the objects were not created Utils_CreateObject or Utils_CloneObject, they will just be removed from the list.
Upon exit, the list is empty.
5) Utils_CallBaseMethod(o, "type", "method", params)
This function invokes the specified base method on an object. This is useful if you have object type hierarchies and have overridden script attributes in derived types and want to still be able to call the overridden script. "o" is the object to invoke the method on. "type" specifies the base type that has the script to be invoked. Note that, as types can not be directly manipulated, there must exist a prototype object for the base type (just an empty object with an "inherit" element will do). "method" is the script to invoke. "params" are the parameters to pass. Pass
null for params if you have no parameters. Otherwise, params should be the standard parameters dictionary passed to a script.
This can especially be useful for cascading "create" and "destroy" calls up the type hierarchy. Actually it's useful for lots of things.
Conceptual notes: Mapping to standard object-oriented terminology, the prototype object is the equivalent of an instantiatable class. (You must still use types to implement derivation. But in order to Clone a type or call a base method on it, you must have a prototype object to be manipulated. If types in Quest are ever made visible like objects, then this requirement can go away.) The "create" script is akin to a constructor, and the "destroy" script is the equivalent of a destructor.
Implementing a "destroy" method in a prototype is straightforward - just add it to the type or prototype object. If you use Utils_CreateObject to create an object that needs a destroy method, you can add it after creation. (I finally discovered about a week ago the elusive "=>" operator to assign an inline script to an object. Very cool!)
Example:
o = Utils_CreateObject("container")
o.list = NewObjectList()
o.destroy => { Utils_DestroyObjectList(this.list) }
item = Utils_CreateObject("item")
item.data = "foo"
list add(o.list, item)
item = Utils_CreateObject("item")
item.data = "bar"
list add(o.list, item)
Utils_DestroyObject(o)
With the "destroy" method added in as above, the two item objects will also be destroyed when the main object is destroyed.
That's about it. If anyone has any questions about this, needs more examples, encounters bugs, or comes up with suggestions, please let me know!