Designing SNIT widgets as mixins

A/AK The purpose of this page is to advocate one particular way of writing SNIT widgetadaptors. I think that this way deserves much more attention than it gets now by miscellaneous Snidget authors.

There is already a lot of useful Snidgets around. It won't take much time before it will become hard to choose between existing alternatives for a given function. Imagine that one text-based widget gives you a decent syntax highlighting, while another one lacks syntax highlighting but provides a wonderful find dialog, the third one has autoscrolling and syntax highlighting but... You've got it.

If there are n independent features that the standard text widget doesn't have, there may be 2^n-1 extended text widgets that implement different subsets of this features.

There is a way to extend existing widgets, fully supported by SNIT from the very start, that doesn't create such a mess. It's rather similar to the approach that many OO systems call mixins: when the particular instance of a class is enhanced in runtime with the functions coming from another class.

There is no extra effort needed to design SNIT widget this way. First, we need to use snit::widgetadaptor instead of a snit::widget declaration. Many programmers seem to avoid using widgetadaptor when the hull widget is either frame or toplevel; but it is evident for me that the choice between widget and widgetadaptor should be made considering the nature of a widget, not only its hull type.

Second (supposed to be the main point of this page, actually), it's sometimes better to leave choosing actual hull type and creating hull widget out of the widgetadaptor. The widgetadaptor's constructor will look like this:

 constructor {args} {
     installhull $win
     $self configurelist $args
 }

This kind of widgetadaptor must be created when the hull widget already exists; when the widgetadaptor's instance is created, the existing widget suddenly gets new methods and/or options and functions.

It turned out to be very effective to design necessary addons for a particular widget type as independent pieces, implementing only a well-defined, highly-specialized function in each widgetadaptor. When you need some combination of those extensions in your application, it will be easy to write something like that:

 undoable [autocontextmenu [filecompletion [entry $path.ent]]]

where undoable, autocontextmenu and filecompletion is a name of your widgetadaptors adding miscellaneous features to an entry.

There's more than that. When you'll need to adapt a widget that is not an entry, but is much like an entry, no change in the widgetadaptor will be required usually:

 undoable [ttk::combobox $path.myCombobox]

(I actually have an "undoable" adapter for entries that runs unmodified with tile entries and various comboboxes).

Having a toolbox of widgetadaptors that don't enforce any predefined hull type is much like working with Unix environment. You don't have to choose between ls with integrated awk scripting and tcl interpreter and another ls that reads zip archives but lacks builtin awk: every tool does its own job, and they all are easily combined when a complex job must be done.


NEM: See also Traits which take a similar approach to composing objects.


ABU 13-feb-2006

Thanks to A/AK for his enlightening discussion. Here are some links about my work with widgetadaptors:


WHD - 2009-09-28 14:24:39

Very cool. I don't tend to do this kind of thing because I worry about performance; each widget adds another layer of wrapping, and it slows things down. But computers are a lot faster now than I first wrote Snit, and maybe I worry too much. :-)


A/AK - 2009-09-29 04:42:00 MSK

I used to worry about performance as well, but with snit2 based on namespace ensemble method dispatching is much faster than before. Once a delegated method is called, it stays in the object's method cache, and in the case of ensembles it means that no TCL code is involved in dispatching it on all further calls. If there were even twenty redirections of this kind, I think it still won't add any significant performance penalty (with snit2 and tcl8.5+).


WHD - 2009-09-30 14:47:04

That was the intent; it's nice to know that it's worked out in practice.


DDG - 2020-04-06

Adding a few example implementations for ttk::treeview mixins.