Purpose: to discuss the structure of the physical code in a Tcl module----

Peter Hiscocks writes in news:comp.lang.tcl :

I hesitate to mention this idea, because it seems so obvious. However, I haven't read it in any of the excellent books on Tcl/Tk and have found it to be extremely useful.

I suggest that any Tcl/Tk program can be broken down into four major sections. As stated in the header from one of my programs:

 # Structure of this program:

 #       Part 1: Definition of all the procedures 
 #       These are used by other sections of the program.

 #       Part 2: Definition of constants

 #       Part 3: Creation of the widgets
 #               - menus
 #               - frames and controls

 #       Part 4: Initialization of system, launching event loop.
 #       This must be at the end of the code because it refers to
 #       procedures and widgets that must be defined previously.

These sections are not necessarily of similar size. Part 1 and 3 tend to be much larger, and Part 4 can be as short as a few lines of code.

This structure clarifies the event-loop based nature of a Tcl/Tk program. You set up the data structures and then start the event loop. What happens after that depends what events are triggered.

It also helps organize the program. For example, the procedures and constants should be known when the widgets are created.

In the body of the code, I indicate the start of each section with something like this:

 #--------------------------------------------------------------
 # Part 4: Initialization
 #--------------------------------------------------------------

These 'section demarkations' can be very helpful in narrowing down the region of the program to search for some particular piece of code.

Comments?

Peter


Donal Fellows replied:

I consider section 3 to be better split between sections 1 and 4, and it is often a good idea to split section 2 off into a separate file so your system installation and configuration applet (:^) can manipulate that more easily.

Much larger programs are better divided up into functional areas, so code manipulating Foobars goes in one file (or even directory if there is a lot of it) and code manipulating Spongs goes somewhere else. This makes maintaining it much easier as you can identify what needs to be fixed with where to look for the code that needs fixing.


Bryan Oakley says:

I tend to not be so formal with naming sections. But what I do do (that always sounds so weird...) is put a main() at the top, and call it at the bottom. I like the main logic to appear first, with the details hidden below. Something like this:

    #!whatever

    <constants get defined here...>

    proc main {} {
        yada yada yada
        foo 420
    }

    proc yada {args} {
        ...
    }

    proc foo {} {
       ...
    }

    main

VL says:

The presented structure is very close to the UIE architecture [L1 ]


I prefer to put the definition of constants and globals at the top of the file. This mirrors C coding style, where your macros tend to appear right at the top. It also follows normal lookup: if you bump into a variable inside a proc you tend to assume it's defined further up so even though this is not required for globals or constants I like to follow the same logic.

--setok

slebetman says:

I kind of like the style set up by vtcl. It goes something like:

 #       Part 1: Definition of all the procedures 
 #               These are used by other sections of the program.

 #       Part 2: Definition of constants

 #       Part 3: Run init proc.
 #               The init proc is responsible for initialising data structures, hiding . or console,
 #               creating images etc..

 #       Part 4: Creation of the widgets

 #       Part 5: Run main proc.
 #               The main proc is responsible for setting up event loops etc, deiconifying . etc..

The init proc lets me collect all the stuff I want to do before creating widgets in a single place. There are things that I sometimes need to do like loading icons & images or reading menu structures from a text file that must be done before creating widgets. All that stuff fits well into an init proc.

Things that needs to be done after creating widgets can then be done in the main proc.


LV So, why would you not define the constants before the procs?


MG July 23 2005 - Personally (and currently, as it's changed a little since I started with Tcl, and will no doubt do so again later), I define all the constants first (but inside a proc), then have a "main" proc, then all the others, like...

 proc setVars {} {
  global varName
  set varName value
 }
 proc main {} {
  # do stuff
 }
 proc otherProcs {} {
  # do stuff
 }
 # run the program
 setVars
 main

The reason I define the constants inside another proc is that, usually, I have a foreach (or a file id from open to set user preferences) or something like that, which uses variables which shouldn't be persistant. Encompassing the whole thing in a proc means that as long as you declare globals where you actually want them, the rest of the cleanup is done automatically at the end of the proc. (And, if you need to restore defaults later, you can just re-run the proc.) There could also be package require statements in there, but where they go depends on the program - sometimes you need to read user prefs before deciding which packages you actually need, etc..


Category Discussion