# Copyright (c) 1993 by Sanjay Ghemawat
#############################################################################
# Class system for Tcl.
#
# Implementation
# * Each object has a name of the form _o_<n> for some integer <n>.
# * _o_next is a global integer variable used for allocating object handles.
# * _o_<n> is a global array that stores the slots for _o_<n>.
# * _o_<n> is a procedure that dispatches to the appropriate methods.
# * <c>_ops is an array of class names indexed by method names.
# * superclass(c) is the name of the superclass for c.
# Initialize global variables
catch {unset _o_next}
set _o_next 0
catch {unset superclass}
# effects - Create class
proc class {name arglist body} {
proc $name {args} [format {
global _o_next
incr _o_next
set self _o_$_o_next
_o_class_create %s $self
eval [list %s.constructor %s $self] $args
return $self
} $name $name $name]
proc $name-with-name {self args} [format {
_o_class_create %s $self
eval [list %s.constructor %s $self] $args
return $self
} $name $name $name]
# Initialization routine
method $name constructor $arglist $body
# Default destructor routine for objects of this class does nothing
method $name destructor {} {}
# Return class name
method $name class {} [format {return %s} $name]
}
# effects - Create subclass. Superclass constructor and destructor are NOT called by default. The subclass constructor and destructor should call them explicitly if necessary
proc subclass {name super arglist body} {
# Make sure the super class is defined
require $super
# Inherit the superclass methods
upvar #0 [set name]_ops sub_ops
upvar #0 [set super]_ops super_ops
# Record super-class name
global superclass
set superclass($name) $super
foreach m [array names super_ops] {
set sub_ops($m) $super_ops($m)
}
# Create subclass
class $name $arglist $body
}
# effects - Delete object
#
# This cannot be a method because Tcl does not like active procs being
# deleted.
proc class_kill {object} {
# Do object-specific cleanup
global superclass
set c [$object class]
while 1 {
$c.destructor $c $object
if ![info exists superclass($c)] break
set c $superclass($c)
}
# Reclaim storage
rename $object {}
global $object
catch {unset $object}
}
# effects - Create method
proc method {class selector arglist body} {
upvar #0 [set class]_ops ops
set ops($selector) $class
proc $class.$selector [linsert $arglist 0 selfclass self] [format {
upvar #0 $self slot
%s
} $body]
}
# effects - Rename method from "old" to "new"
proc rename_method {class old new} {
upvar #0 [set class]_ops ops
set ops($new) $ops($old)
unset ops($old)
rename $class.$old $class.$new
}
# effects - Invoke selected method in superclass context
proc super {selector args} {
global superclass
upvar self self selfclass selfclass
set sup $superclass($selfclass)
upvar #0 ${sup}_ops ops
return [uplevel [list $ops($selector).$selector $sup $self] $args]
}
# effects - Used internally for object creation. Takes class name.
proc _o_class_create {C self} {
upvar #0 $self slot
catch {unset slot}
set slot(junk) {}
unset slot(junk)
proc $self {sel args} [format {
global %s_ops
return [uplevel [list $%s_ops($sel).$sel $%s_ops($sel) %s] $args]
} $C $C $C $self]
}
proc require {procname} {
if ![string compare [info commands $procname] $procname] return
auto_load $procname
}SS Nice! this runs with a minor change (using concat instead of linsert that's still not implemeted) with Jim! so it's the first OOP extension available for it ;)

