Coding Beyond The Screen, Part I

Coding Beyond The Screen, Part I November 15, 2014

Quill I’m sitting in Portland International waiting for my flight after the end of the Tcl/Tk conference, so it seems an appropriate time to continue my series on software aesthetics. Previously I talked about writing individual procedures, small and large. But what about entire modules—files—of code?

Some modules are simply one utility procedure after another with a header comment at the top. Those are straightforward. More often, though, I prefer to implement a module as an ensemble command: a Tcl command with subcommands. This gives the whole module a single entry point (the module name) and all of the subcommands are clearly and visibly related together.

The standard Tcl dict command is an example of an ensemble command. A dictionary is similar to an array in other languages, but an array that can be indexed on any value. Dictionaries are often used to store records of data:

set rec [dict create]

dict set rec firstname Joe
dict set rec lastname  Blow
dict set rec age       42

if {[dict get $rec age] > 18} {
    puts "Person is old enough to vote."
}

Here, we use three of the dict command’s subcommands: dict create, dict set, and dict get. (You’re right; I didn’t add color to the code today. My bad.)

There are many ways to implement ensemble commands; my preferred method is to use the Snit package’s snit::type mechanism. Usually, snit::type defines an object type with instances, rather like a class in other languages; but it can also define a singleton object. And since the standard way of representing an object in Tcl is as a command with subcommands, the singleton object is an ensemble.

Here’s an excerpt from Quill’s project module, which is responsible for retrieving the project’s metadata from disk and making it available to other modules:

snit::type project {
    pragma -hasinstances no -hastypedestroy no

    # meta - Project metadata array for the project 
    # being managed.
    #
    # project       - The project name
    # version       - The project version number
    # description   - The project description

    typevariable meta -array {
        project     ""
        version     ""
        description ""
    }


    typemethod name            {} { return $meta(project)     }
    typemethod version         {} { return $meta(version)     }
    typemethod description     {} { return $meta(description) }
}

I’ve remove most of the comments and most of the code from this listing, because I’m trying to illustrate the concept. This code is contained in project.tcl, and defines a snit::type called project. The type includes a “type variable”, meta, which contains metadata about the project (far more than is shown here). It also defines “type methods”, which are essentially Tcl procedures that define subcommands of the type command. Here we define three type methods, to return the project’s name, version number, and description.

Another module in Quill might use these commands like this:

puts "Building project:"
puts "Name:     [project name]"
puts "Version:  [project version]"
... code to build the project ...

Next time, I’ll talk about the structure of a singleton module.

____
photo credit: campra via photopin cc


Browse Our Archives