This chapter focuses on the concepts of classes, objects and
messages, the basis of the [incr Tcl] language.
Problem solving using [incr Tcl] involves classifying objects according to their similarities and differences. A class defines the behavior of similar objects by specifying their insides--the variables they contain and the methods available for responding to messages sent to them.
Every object is an instance (member) of a class.
An object's internal variables are called instance variables;
they are themselves containers for other objects.
A Point refers to a position within a two-dimensional array. It has two instance variables: x, the horizontal coordinate, and y, the vertical coordinate. In order for a graphics tool to address the pixels on a display or output device, there must be a coordinate system imposed on the device. The coordinate system used by Smalltalk/V is shown in Figure 3.1.
Figure 3.1
Coordinate System
To evaluate the following source-code, start the program tkcon and enter (or copy and paste)
the lines to the prompt (%).
package require Itcl
itcl::class Point {
variable x
variable y
constructor {{aNumberX 0} {aNumberY 0}} {
set x $aNumberX
set y $aNumberY
return $this}
method x: {aNumber}
method y: {aNumber}
method x {}
method y {}
method is {aNumberX aNumberY}
method printOn: {aStream}
method printString
method = {aPoint}
method += {aPoint}
method + {aPoint}
}
The command "package require Itcl" loads the [incr Tcl] extension.
The "itcl::class" command starts a class definition. The class Point
has the variables x and y. The methods will be explained shortly. With
the source code above it is possible to create Point objects.
Copy and paste the following lines to the prompt:
Point a 5 10
Point b
The first line creates a Point object a with the coordinates 5 and
10. The second line creates object b with default coordinates 0 and 0.
See the constructor definition above.
All access to the variables in a class is done through access methods. To set the variables to a value execute the following:
itcl::body Point::x: {aNumber} {
set x $aNumber}
itcl::body Point::y: {aNumber} {
set y $aNumber}
a x: 1
a y: 2
The variables x and y of object a have now the values 1 and 2. To get the variables some more access methods are needed
itcl::body Point::x {} {
return $x}
itcl::body Point::y {} {
return $y}
a x
a y
The use of x: y: methods to set a Point object are inconvenient. Some better set method is:
itcl::body Point::is {aNumberX aNumberY} {
set x $aNumberX
set y $aNumberY}
a is 1 2
To get a string representation of the object there is the printString method:
itcl::body Point::printString {} {
return "$x @ $y"}
puts "[a printString]"
For output to a stream there is the printOn: method. The console window is the stream stdout.
itcl::body Point::printOn: {aStream} {
puts -nonewline $aStream "$x @ $y"}
a printOn: stdout
The method = copies a Point object.
itcl::body Point::= {aPoint} {
set x [$aPoint x]
set y [$aPoint y]}
b = a
puts "[a print] ; [b print]"
The above methods are typical for most classes. The following methods implement the algorithms. The increment a Point object is the first:
itcl::body Point::+= {aPoint} {
set x [expr $x + [$aPoint x]]
set y [expr $y + [$aPoint y]]}
a += b
puts "[a print]"
The sum method has to create a new Point object. This is done with
#auto, a build-in method in every [incr Tcl] class.
itcl::body Point::+ {aPoint} {
set sum [Point #auto]
$sum x: [expr $x + [$aPoint x]]
$sum y: [expr $y + [$aPoint y]]
return $sum}
Point c
c = [a + b]
puts "[c print] = [a print] + [b print]"
Many more methods can be added to the Point class. But the class concept should be clear now: bring data and algorithms together in one housing. This housing introduces a new abstraction level to programming.
A Set stores arbitrary objects. A Set
does not store the same object more than once. The Set class definition
is:
package require Itcl
itcl::class Set {
variable contents ""
method add: {anObject}
method do: {varName aBlock}
method includes: {anObject}
method remove:ifAbsent: {anObject aBlock}
method size {}
}
Set s
The method add: adds one object to the set.
itcl::body Set::add: {anObject} {
# "Answer anObject. Add anObject to the receiver
# if the receiver does not already contain it."
if {[lsearch $contents $anObject] < 0} {
lappend contents $anObject
}
return $anObject}
s add: 1
s add: "anton"
s add: {"Mona" "Lisa"}
s add: 3.0
s add: "anton"
s add: 3.0
The do: method is a new control structure like the foreach command.
itcl::body Set::do: {varName aBlock} {
# "Answer the receiver. For each element in the receiver,
# evaluate aBlock with that element as the argument."
upvar $varName v
foreach v $contents {
uplevel $aBlock}}
s do: element {puts "$element"}
The includes: method is a test.
itcl::body Set::includes: {anObject} {
# "Answer true if the receiver includes anObject
# as one of its elements, else answer false."
if {[lsearch $contents $anObject] >= 0} {
return 1
} else {
return 0}}
puts [s includes: 3]
puts [s includes: 3.0]
puts [s includes: {"Mona" "Lisa"}]
The remove:ifAbsent: removes an object. The block is evaluated if
there is no object to remove.
itcl::body Set::remove:ifAbsent: {anObject aBlock} {
#"Answer anObject. Remove the element anObject from
# the receiver collection. If anObject is not an
# element of the receiver, aBlock is evaluated
# (with no arguments)."
set index [lsearch $contents $anObject]
if {$index < 0} {
return [uplevel $aBlock]
}
set contents [concat \
[lrange $contents 0 [expr $index-1]] \
[lrange $contents [expr $index+1] end]]
return $anObject}
s remove:ifAbsent: "anton" {puts "nothing to delete"}
s remove:ifAbsent: "anton" {puts "nothing to delete"}
The size method returns the number of elements in the set.
itcl::body Set::size {} {
# "Answer the number of elements contained
# in the receiver."
return [llength $contents]}
puts [s size]
This example for a Set class is not complete. But now there are
enough objects and messages to talk about in the system.
At this point, you should be familiar with:
If you want to review any of these topics, simply refer back to the appropriate section in this chapter.