Programming Techniques from 7B Software, Inc.

Home

Contact

About 7B Software, Inc.

Professional Resume

Notable Hacks
from 7B Software

Programming Techniques
from 7B Software

Links and Resources

In this page I'd like to describe some of the more interesting technical problems that I've solved over the last few years. I hope you find some of these ideas helpful.

Tcl/Tk Style Guide

I wrote this Tcl/Tk Style Guide as a result of several phenomena I've noticed in the industry:
  • Tcl/Tk codebases tend to "tip over" and become unmaintainable at the 10K - 20K SLOC barrier.
  • Tcl/Tk is an easy language to get yourself in trouble. There are places in the language where you are better off staying away from.
  • Conversely, there are Tcl/Tk language features that should be a standard part of the arsenal; they yield code that does scale to large projects.

Tcl/Tk Performance Techniques

  • Don't use the "-command" option in the lsort command. This option will always result in a slow sorting operation. Actually, that's rather well-known to Tcl programmers. But what you might not realize is something a little more insidious: This option might only become a big problem only when your program has to deal with real data. (You know, when you do your initial testing, you typically do it on small-sized data sets. But when you get closer to delivering production code, you find that you have to deal with large, real-world data sets. By that time it can be difficult to find a good alternative!)

    Suggestion: Either use one of the other lsort options (often the "-index" option will do what you want), or if that's not possible, do the sorting directly in C or C++. And test your sorts early in the development process to weed this problem out.

  • Don't use the "array names arrayName PATTERN" idiom. It's not too surprising that this particular operation is linear on the number of elements in the array. What is a bit surprising is how easily this construction can negatively affect the performance of your program.

    This is kind of a shell game phenomenon. After all, you may have used an associative array precisely because you wanted to avoid the linear lookup that a Tcl list would have given you. The problem is that you will immediately give back your performance gain if you use the PATTERN when looking up elements in the array!

  • You may have to implement computationally intensive parts of your program in C or C++. Again, this is no surprise. But it can be rather hard to even identify which parts of the program are in fact taking up the time. I suggest that you use either the Tcl time command, or that you download the Tcl profiler.

  • Be aware of the Tcl compiler. The speed of your program usually will greatly depend upon writing code that the Tcl compiler will optimize into bytecodes. The simple rule of thumb is to always put braces around arguments to the if and expr commands; e.g.:
        set a [expr {($b + $c)/2}]
        if {[meets_condition $d]} return
    
    instead of
        set a [expr (($b + $c)/2)]
        if [meets_condition $d] return
    

  • Canvas widget. The canvas widget traverses tags in linear time, not constant time. This means that if you have a huge canvas with lots of tags, you can quickly get into the soup, performance-wise.

    If you're having canvas performance problems like this, you may have to consider eschewing Tk canvas tags, and instead implement them in your application using associative arrays.

  • Other techniques can be found in the Tk Performance or in the Tcl Performance sections of the Tcl Wiki website.

Tcl/Tk Coding Techniques

  • Use namespaces. One of the biggest gripes about Tcl has always been its uncontrolled, "scripty" nature. This is often viewed as a benefit when tossing together a quick prototype--but is a decided weakness when fielding a large production program.

    The Tcl namespace feature helps to manage the maintenance of a Tcl program, making programs in the language roughly as maintainable as a C programs. It does this by allowing the programmer to define modules that contain the equivalent of static variables and procedures, thus reducing the need to define variables and procedures in the global scope. This in turn can considerably shrink the time needed to locate and fix a program bug, since large portions of the program can usually be ignored for any particular bug.

    In order to use namespaces effectively, though, the Tcl program should make use of the convention that all namespace variables should be written only within a single file that defines that namespace. Otherwise, the desirable "bug locality" of the Tcl program is lost, even if namespaces are utilized.

  • Don't use "update" when "update idletasks" is what you want. "update" will see if there are any events to process, while "update idletasks" will just run any idle tasks waiting to run. Typically, those idle tasks will cause outputs to be flushed to the screen, though of course an idle task can do anything.

    So, what's the difference really?

    The difference is, your program is in control (pretty much anyway) if you just use "update idletasks". But the user has control if you use "update". That means that after an "update", you must test the existence of any non-local resource, including (especially) the existence of any window that your program uses. E.g.:

        toplevel .t
        # ...create the window children of .t 
        update
        focus .t   ;# UNSAFE, usually
    
    The problem is that the user may have dismissed .t during the update.

    The same comment goes for the vwait command, too; during vwait, events from the user will be processed.

  • Remember, native Tcl is not a threaded langauge. Tcl is an event-driven language with a single stack. While your program processes an event, it can use update or vwait to suspend the event processing, allowing a new event to be processed while the original event's context is pushed onto the execution stack. But if the new event's execution is also suspended (using, say, another vwait), the original event's execution will not be restarted. It won't be restarted until the new event's execution completes. Don't con yourself into believing that your program has magically become threaded in cases like this!

  • If you expect your Tcl/Tk program to work on Windows and Unix, be prepared to do some extra work. The Windows implementation of Tk has historically not been as robust as the Unix implementation--not surprisingly, since its roots are entirely in Unix. Though the Windows implementation is getting better and better, there are some areas that still must be dealt with.

    First, you will probably have to code at least part of your program in C or C++. This is especially true if you are making a custom widget, or an extension to an existing widget. Typically in these programs you will have a display function. I have never seen a case where a widget display function will be fast enough under Windows if it isn't coded in C or C++.

    Second, you will probably have at least one window layout that you should create once and withdraw when dismissed. This is because Windows is notoriously slow in creating new subwindows.


Member, Association
for Computing Machinery
Last updated: July 30, 2010