oo::class , a built-in Tcl command, is the class of all classes in TclOO. All classes are instances of this class. Consequently, oo::class is an instance of itself.
↳ oo::object ↳ oo::class
dzach: If for some reason the creation of a new object cannot be fulfilled, the constructor can be aborted by using return -code break. This just returns an empty string, instead of an improperly initialized object. Are there any implications of using return -code break in this manner?
AMG: Is there a compelling reason why [oo::class new] is hidden?
DKF: Because everyone treats classes as named entities with long lifetimes. Expose it if you want.
AMG: How do I do this? Sorry, I'm a total TclOO newb. :^)
DKF:
oo::define oo::class export new
Note that this does it for all classes. It might be better to do this instead:
oo::define oo::class self export new
This only exports it for oo::class itself.
AMG: Can I define a destructor for a class? Automatically deleting all subclasses, instances, and "mixees" is good, but I'm working on a project that needs some additional cleanup when a class is destroyed.
DKF: Yes. The simplest technique is to make your class an instance of a subclass of oo::class and attach the destructor to that.
oo::class create class-with-destructor { superclass oo::class destructor { puts "bye!" } } class-with-destructor create MyClass { # ... }
But if you've already got your class instance, do not despair! You can inject the destructor through modifying the class instance's superclass with oo::objdefine:
oo::objdefine MyClass class class-with-destructor
If you're changing objects' classes, remember that classes cannot be changed to non-classes or vice versa, and both oo::object and oo::class cannot have their class changed (they're special, for the sake of sanity). (And this is something where a mixin won't work; mixins are currently ignored for destructor processing, and while maybe that shouldn't be so, it's how things are now.)
AMG: Wait a second, according to [L1 ], "the destructor is called when objects of the class are deleted". I want a destructor for when the class itself is deleted.
DKF: Yes. I know:
% oo::class create class-with-destructor { superclass oo::class destructor { puts "bye!" } } ::class-with-destructor % oo::class create foo { destructor { puts "killing [self]" } } ::foo % foo create bar ::bar % oo::objdefine foo class class-with-destructor % foo create bar2 ::bar2 % bar2 destroy killing ::bar2 % foo destroy bye! killing ::bar
Is that not what you want? (Note that class destructors are processed before instances; guaranteeing order to be the other way is somewhat tricky…)
AMG: No, it's not what I want. I want to schedule code to run when [class-with-destructor destroy] is invoked, or the class is destroyed by other means (e.g. rename to ""). I have external data associated with the class (not the instances), and that external data needs to be cleaned up when the class goes away.
DKF: Yes, and that means you want a destruction callback on the relevant class object instance. Currently, we only support defining destructors on classes and not instances (even if those instances are instances of oo::class, i.e., classes) so we have to fake it. The easiest way to fake it is to make a one-of-a-kind metaclass that only the class of interest will be an instance of. You're fixating on class-with-destructor (the mechanism) when you should be looking at foo (the class that stands in for what you want).
You need to beware, as destructors can be run in a state where invoking methods on the object being destroyed is impossible. It can't be helped; some ways things can die are just tricky. If you can use the attached metadata mechanism, exposed in the C API only, that makes deleting things much simpler as you get an explicit callback for “delete this piece of data” if you desire.
DKF: Of course, the other way is to just put a command delete trace on the class instance's command:
trace add command MyClass delete DeletedMyClassCallback…
Don't know whether that will fire before or after the class actually goes away.
2015-04-29 bll Some notes on object destructors: Object variables do not fall out of scope and are not destroyed upon scope exit. The destructor is not called upon exit of the program. The destructor is not called when the last reference to the object is cleared. e.g.
set o [myobj new] unset o ; # destructor is not called