Application Base Project

written 15 Nov 1999 being revised May 2006
Google site search

ContentsIntroductionBasicIntermediateAdvancedFuturePolicyInfrastructure

1   Introduction        

This project is probably showing its age as new menu widgets are now available to simplify this project. However this project is still basic to the start of writing any application.

1.1   Overview        

This is an essential programming exercise for anyone going on to do further programming projects of an kind. Typically for 1st, 2nd or 3rd Year High School Students specialising in learning about computer programming.

Each student works alone to produce his/her own application base program. The source of this program can then be used as a basis for other more complex programs.

This project can be done as a single student as a personal project, or by a class.

Most of the project tuition is taken up in explaining what Object Oriented Methodology is. Describing concepts such as object, method, encapsulation, module, property and inheritance. The project shows how these ideas are incorporated into an object written in the programming language Tcl and which can be reused for other projects.

1.2   Resources Required        

A PC type computer and the freely available Tcl interpreter are required. A small slow computer is adequate for this project for a small group of students. Any of the UNIX, Windows or Mac OS's can be used and the product will port and run on all these systems. This is a short practical exercise where much of the work is homework and could possibly be done in a one hour class.

1.3   Prerequisite knowledge        

The students should already be familiar with the basic concepts of Tcl and have done the Text Editor project or something similar.

1.4   Prohibitions        

Students interested in advanced computer subjects which do NOT involve actual programming or program design need (should) not do this course as they will never really use what is learned. Though the idea of design in modular methodology is a general design skill, the general principles learnt could be of some use.

2   Lesson 1 - Cannibalising        

First we "cannibalise" the Text Editor application to extract the framework for any basic application. This consists of application window, with menu bar with New, Open, Save, Save As and Help functions. In this application the objects being saved will be saved in the form of Tcl/tk scripts, basically a text format.

The process of cannibalisation is an important one for generating general solutions derived from the solution of specific problems in the past for reuse. This ability to extract from past solutions, the components that help us solve new problems in a general manner is called "generalisation" in Mathematics. And the abiltiy to create clear cut general modules from a specific program solution is a comparable skill in computer programming which should be promoted and refined. This is how the building blocks of very complex program projects are built up.

The general idea is that the product of this exercise should be a program that can easily be used as the basis for any new application without any great modification.

Tcl provides several facilites that make code reuse easier. The source command allows new segments of program to be loaded while the program is running. It also allows for procedures to be redefined during the programs execution and this is the key to allowing reuse of existing code without changing it. This process can be abused of course and good coding practice should be promoted, but it is useful for initailly sketching out a program, to be replaced with specific code later.

The first step is to draw a line through the text editor program at the point where the code changes from being general to the point where it is specific to a text editor. In particular, any part of the program which refers to the text widget is peculiar to the text editor. This include the newFile, saveFile and loadFile procedures and the contents of the Help text widget. This gives us the following code:

#Application Base - Canniblised Text Editor

#Procedures
set initialdir "/tcl"
proc fileDialog {w operation} { global initialdir
    #   Type names		Extension(s)	Mac File Type(s)
    #
    #---------------------------------------------------------
    set types {
	{"All files"		*}
	{"Tcl Scripts"	{.tcl .tk}			}
	{"HTML files"	{.htm .html .shtm .shtml}	}
	{"Text files"	{.txt .doc}	}
	{"C Source Files"	{.c .h}		TEXT	}
	{"All Source Files"	{.tcl .tk .c .h}	TEXT	}
    }
    if {$operation == "open"} {
	set file [tk_getOpenFile -filetypes $types -parent $w -initialdir $initialdir]
        
    } else {
	set file [tk_getSaveFile -filetypes $types -parent $w -initialdir $initialdir \
                 -initialfile Untitled -defaultextension .tk]
        
    }
    if {$file != ""} {set initialdir [file dirname $file]}
    return $file
}

set w {}
set title "My Text Editor 7"
frame $w.menu
pack $w.menu -side top -fill x

button $w.menu.new -text New -command {newFile}
button $w.menu.open -text Open  -command {loadFile [fileDialog . open]} 
button $w.menu.save -text Save -command {saveFile $filename} 
button $w.menu.saveas -text "Save As" -command {saveFile [fileDialog . save]} 
pack $w.menu.new $w.menu.open $w.menu.save $w.menu.saveas -side left
button $w.menu.help -text "Help" -command help
pack $w.menu.help -side right

text .text -relief raised -bd 2 -height 20 -yscrollcommand ".scroll set"
scrollbar .scroll -command ".text yview"
pack .text -side left -fill both -expand 1
pack .scroll -side left -fill y

# Load initial file
if {$argc==1} {loadFile [lindex $argv 0]} else {newFile}

proc help {} { global title
    if { ![winfo exists .help] } {
    toplevel .help
    wm title .help "$title Help"
    wm transient .help .
    text .help.text -relief raised -bd 2 -height 20 -yscrollcommand ".help.scroll set"
    scrollbar .help.scroll -command ".help.text yview"
    pack .help.text  -side left -fill both -expand 1
    pack .help.scroll -side right -fill y

    .help.text tag configure H1 -font {Helvetica 18 bold}
    .help.text tag configure H2 -font {Helvetica 15 bold}
    .help.text tag configure H3 -font {Helvetica 12 bold}
    .help.text tag configure H4 -font {Helvetica 12 normal}
    .help.text tag configure H5 -font {Helvetica 10 bold}
    .help.text tag configure H6 -font {Helvetica 8 bold}
 
    }
}

3   Lesson 2 - Encapsulating        

The code above could simply be extracted to another file and sourced into the start of any new application you write. And for a small personal application this is a useful way to start. But you need to be aware of what variables need to be set and what procedures need to be provided before this file can be used in another program. There are quite a few variables and procedures that span the boundary represented by the seperation of the code. The way that the variables and procedures are required to integrate with the application as a whole and the object varies and is not clear to someone else trying to reuse this piece of cose, nor maybe even to its author in 1 years time. For instance it is not clear what the effect of changing a variable like filename will be on the behaviour of the Appliaction Base. Nor is it even apparent that Application Base might use filename in a special way.

Object Encapsulation is the process whereby the boundary of the Object is made firm so that the way variables are used is made clear to the programmer.

3.1   Encapsulating Namespace        

In Tcl most variables are known globally and it is easy for names to be reused inadvertently. So a naming scheme is adopted which helps to avoid this. A numbr of different methodologies are used by different people, but they all tend to consist of prefixing variable and procedure names with an Object Name Qualifier in a way that makes the reference to a variable or procedure "owned" by an object obvious.

Tcl leads the way by using its own paradigm. You will notice looking at the Tcl Help Manual on-line that there are many procedure called Tk_.... and tcl_... and I will promote continuing to use the same paradigm. The Tcl paradigm is to use a first letter capital prefix for C routines and a lowercase first letter for Tcl procedures, and we will honour this method also. So the first step is to prefix all the variables used in the Application Base by the prefix appBase_. This still leaves us with the problem of deciding which variable are to be considered to be "owned" by the object. To start with rename everything in the code above in Lesson 1, but for the Text Editor to still work variable names will have to be changed there as well. Make changes to the Text Editor and verify that it still runs OK. In this way we test that our design paradign works in practice.

Many program languages provide special features for managing object namespaces, but they create a layer of complexity that is not usually worth the effort except for very large projects. Tcl has such a system called the namespace subsystem, but it also is too complex to be useful for the programs that we are working with here.

3.2   Encapsulating Behaviour        

Changing the names in the Text Editor highlights the variables which are not well encapsulated in the Application Base. title and filename are obvious instances. Steps should be made to identify variables which rightly belong completely inside the object but which are currently straying outside. filename is an example. It is being used and set in lots of procedures both in Appliaction Base and outside, but in fact it can be put completely inside the object. The code associated with filename can be taken out of the saveFile loadFile and newFile procedures and put into intermediate procedures inside the Application base. The result is that the file procedures are now simpler and their function more clearly defined. At the same time the check for a null filename can also be removed. This is a good example of the process of encapsulation simplifying programming tasks.

If a variable is being used and changed both inside and outside the object, and cannot be encapsulated into the object completely, then the object boundaries need to be reconsidered.

3.3   Initial Values and Object Creation        

The variable title is used both outside and inside the Application Base. The Application Base needs some title defined even if it is blank, but the Application will always want to define its own name. If the apppliaction sets title and then sources appBase.tk the title will be overwritten by the Application Base defaults. If title is set after sourcing appBase.tk then the title bar wont be set unless that function is done both inside and outside the object. This is messy and goes against encapsulating behaviour. The solution is simple. All objects have to be created by the applications that own them. When this occurs they typically return a value representing the unique name of the object. At the same time intial values for the object can be defined by the application.

This can be seen in the Tk widgets in which an initial call is made to a procedure like button to create a button widget with the desired properties and behaviours. The Tk widgets use commands that have keyword references. This form of command is more difficult to program than a simple procedure call where specific parameters are used. We will use the simple approach here. Basically the code that would be executed when app_base is sourced is put into a create procedure. When we attempt to do this we come up against a problem. The code inside the object which attempts to read an initial file causes problems. With appBase_create call at the head of the program the text widget into which the file is to be loaded doesnt exist yet. If we move the call further down the program the menu bar gets displaced. Attempting to load an initial file in the create pahse makes assumptions about what has already happened in the main program. This function has to be taken out of the create procedure and moved to the application where it more properly belongs since it uses $argc and $argv variables.

At the same time the application procedure names for new save and load Files can be passed across at initialisation, making for even more encapsulation.

The create procedure now looks rather cumbersome with a lot of global variables and initial assignments. This can be addressed by creating an AppBase array which contains all the variables which define the Application Base objects attributes. This array can then be queried to see what attirbutes exist before attempting to access them outside the object if the need arises.

Now that the object behaviour has been disentangled from the application we can see how to condense the saveFile and loadFile procedures back into the fileDialogue procedure. The code now looks something like this:

#Application Base - Encapsulated
#Procedures

proc appBase_fileDialog {w operation} { global appBase_initialdir
    #   Type names		Extension(s)	Mac File Type(s)
    #
    #---------------------------------------------------------
    set types {
	{"All files"		*}
	{"Tcl Scripts"	{.tcl .tk}			}
	{"HTML files"	{.htm .html .shtm .shtml}	}
	{"Text files"	{.txt .doc}	}
	{"C Source Files"	{.c .h}		TEXT	}
	{"All Source Files"	{.tcl .tk .c .h}	TEXT	}
    }
    if {$operation == "open"} {
	set file [tk_getOpenFile -filetypes $types -parent $w -initialdir $appBase_initialdir]
        
    } else {
	set file [tk_getSaveFile -filetypes $types -parent $w -initialdir $appBase_initialdir \
                                  -initialfile Untitled -defaultextension .tk]
        
    }
    if {$file != ""} {
          set appBase_initialdir [file dirname $file]
           wm title . "$appBase(title) - $file"
           set appBase(filename) $file    
           $appBase($operation) $file
    }
    return $file
}

proc appBase_create { title initialdir new save open} { 
     global appBase
     foreach i { title initialdir newFile saveFile loadFile} {
           set appBase($i) [set $i ]
     }
     
     set appBase(filename) ""
     wm title . $title
      frame .menu
     pack .menu -side top -fill x

     button .menu.new -text New -command " set appBase(filename) {}; wm title . $title; $new "
     button .menu.open -text Open  -command {appBase_fileDialog . open} 
     button .menu.save -text Save -command {$appBase(save) $appBase(filename)}
     button .menu.saveas -text "Save As" -command {appBase_fileDialog . save}
     pack .menu.new .menu.open .menu.save .menu.saveas -side left
     button .menu.help -text "Help" -command help
     pack .menu.help -side right
}

proc help {} { global appBase_title
    if { ![winfo exists .help] } {
    toplevel .help
    wm title .help "$appBase_title Help"
    wm transient .help .
    text .help.text -relief raised -bd 2 -height 20 -yscrollcommand ".help.scroll set"
    scrollbar .help.scroll -command ".help.text yview"
    pack .help.text  -side left -fill both -expand 1
    pack .help.scroll -side right -fill y

    .help.text tag configure H1 -font {Helvetica 18 bold}
    .help.text tag configure H2 -font {Helvetica 15 bold}
    .help.text tag configure H3 -font {Helvetica 12 bold}
    .help.text tag configure H4 -font {Helvetica 12 normal}
    .help.text tag configure H5 -font {Helvetica 10 bold}
    .help.text tag configure H6 -font {Helvetica 8 bold}

    }
}

4   Lesson 3 - Reaping the Rewards        

When writing a program to get a job done we often make do with basics. The Text Editor is such an example. If you compare the File dialogue behaviour to that of the MS Notebook you will notice a lot of rough edges.

It takes a lot of extra effort to design an object and encapsulate its behaviour. But if the need is seen, then it repays effort many times over. Often we are prepared to live with rough edges to get a particular job done. But when we create an object for reuse it starts to pay to get everything right. But this doesnt need to be done immediately. An object can be developed and improved over time with the knowledge that every small improvement will benefit a lot of programs.

At the end of the Text Editor Exercise were some suggestions for further development. A lot of these were for the Application Base Object

©2000 - 2006 WEBSCOOL This page last updated 30 May 2006. All rights reserved - including copying or distribution of any portion of this document in any form or on any medium without authorisation. For more regarding the copyright.