Optimizing Snit

SG2: I've been using snit for a while (pre-1.0/pre-tcllib inclusion), and I really like it. But I've run into a case where it's performance overhead may be a little too much, so I'm starting to think about ways to optimize my snit code. I'm already using macros heavily, and I've investigated Snit 2.0 which, as promised, cleans up the stack trace (a lot) and gives some (a little) performance improvement, but not as much as I was hoping for. Plus, I'm reluctant to use an alpha (8.5) in production and it's not clear when 8.5 will be officially released.

As an aside, Tcl 8.5 seems a bit slower in general, so I don't know if the Snit performance gains are obscured by something else that has slowed down.

Are there any standard strategies for optimizing snit?

Typically, when Tcl's too slow, I reimplement as a C extension, but it's not clear to me how to define a snit method as a C command. Is there a supported way (i.e., not digging into snit's implementation) to do this? Ideally, a way that would work for both Snit 1.x and 2.x? Most of the code isn't performance critical, just a few methods so it would be a shame to have to reimplement the entire object in C just to speed up a method or two.

Alternatively, is there a supported way to redefine or add a method to an object instance at "run" time (i.e., after snit::type has been executed and the constructor invoked)? Actually, this would be useful in a variety of contexts beyond performance optimization.

WHD: There are a number of things you can do that will help. The first is in the matter of design. I tend to use Snit to encapsulate large components, rather than small ones. In Java or C++ it's common to have thousands of objects in one program; my programs tend to have fewer than a hundred. If you design your program with thousands of small objects with complex inter-relations and lots of delegation, performance is indeed disappointing. So what I do is design large objects with clean interfaces--and use standard Tcl programming techniques to structure the data inside. I'd never use a Snit object simply as a record structure, one instance per record, for example; though I might define a Snit object that managed a collection of records, storying the data in an array.

There are some other things you can do. The main thing is to be aware that there's a run-time penalty for every type variable and instance variable you define in the type definition, simply because the variables are implicitly declared in every method. One alternative is not to define them in the body of the type definition, but to declare them explicitly using "typevariable" and "variable" in the specific methods that need them. Some folks prefer that. Me, rather than defining lots of scalar variables I'll story them all in an array, which I'll often call "info". Then I can define as many scalars as I like, but only pay the runtime penalty for implicitly declaring a single variable.

I have hopes that some new Tcl 8.5 features will help me to solve the variable declaration overhead...but that's for the future. (I wouldn't worry about Tcl 8.5's speed, by the way; until it's closer to feature-complete, they won't be trying to optimize it.)

SG2: Thanks for the advice. I hadn't really thought through the performance implications of variables. I didn't realize that I could use "typevariable" and "variable" in a method body. Is snit's "variable" command synonomous with Tcl's "variable" command? Is it legal to invoke snit's "method" command from within a method body to define (or redefine) an instance method?

WHD:"variable" is a special Snit command that mimics ::variable. "typevariable" is simply an alias for ::variable, since typevariables are variables declared in the type's namespace.

And yes, you can use "snit::method" to define or redefine methods from within a method body--but the arguments for "snit::method" are slightly different from those for "method" within a type definition. See the man page for details.

SG2:Thanks, but that "snit::method" modifies the method for all instances of the type. Is there a way to create/modify a method just for a particular instance?

Looking at the code, I believe I could create a method in the instance's namespace, and seed the instance's method cache. But that really would involve reaching into the internals, and probably wouldn't be snit 2.0 compatible, huh?

Any interest in extending snit to support per instance methods?

WHD:Using "delegate method" you can delegate unknown methods to a specific handler, passing the unknown method name as an argument. You could have your handler dispatch methods differently for different instances. That's about all you can do at the moment, though.

WRT extending snit to support per instance methods, you'd be better off waiting for the new oo:: package in Tcl 8.5. It's supposed to have them, and it should be much faster than Snit.


AK: Something I sometimes try is to look at a method and check if it is actually using any of the (type)variables. If not I change it from a method into a proc. Less call overhead, no implicit declaration of variables. Of course, procs cannot be delegated, or be target of delegation. But they are usually internal stuff anyway. I may do the method -> proc conversion for methods which use only one or two of the instance variables as well, using upvar to access them (names given via explicit proc arguments).

Sarnold: If you want to optimize a method that does not need access to instance variables, but does for type variables, you should declare it as a typemethod. Why? Simply because typemethods can be delegated.


See also Snit emulations : Itins and Xoins.

SG2: How robust are either of the emulations?

Sarnold: Itins is abandoned because [Incr Tcl] is not flexible enough. Xoins is still maintained and runs with a little modification many mega-widgets and widgetadaptors. With Xoins, most of the Snit types can be switched by simply replacing snit::type by xoins::type. See the page on the wiki for more details.