Documentation generated from CVS HEAD
itcl::extendedclass -
create a extendedclass of objects
This is new functionality in [incr Tcl] where the API can still change!!
itcl::extendedclass extendedclassName { inherit baseExtendedclass ?baseExtendedclass...? constructor args ?init? body destructor body public method name ?args? ?body? protected method name ?args? ?body? private method name ?args? ?body? public proc name ?args? ?body? protected proc name ?args? ?body? private proc name ?args? ?body? public variable varName ?init? ?config? protected variable varName ?init? ?config? private variable varName ?init? ?config? public common varName ?init? protected common varName ?init? private common varName ?init? public command ?arg arg ...? protected command ?arg arg ...? private command ?arg arg ...? <delegation info> see delegation page <option info> see option page set varName ?value? array option ?arg arg ...? } extendedclassName objName ?arg arg ...? objName method ?arg arg ...? extendedclassName::proc ?arg arg ...?
The fundamental construct in [incr Tcl] is the extendedclass definition. Each extendedclass acts as a template for actual objects that can be created. The extendedclass itself is a namespace which contains things common to all objects. Each object has its own unique bundle of data which contains instances of the "variables" defined in the extendedclass definition. Each object also has a built-in variable named "this", which contains the name of the object. Extendedclasses can also have "common" data members that are shared by all objects in a extendedclass.
Two types of functions can be included in the extendedclass definition. "Methods" are functions which operate on a specific object, and therefore have access to both "variables" and "common" data members. "Procs" are ordinary procedures in the extendedclass namespace, and only have access to "common" data members.
If the body of any method or proc starts with "@", it is treated as the symbolic name for a C procedure. Otherwise, it is treated as a Tcl code script. See below for details on registering and using C procedures.
A extendedclass can only be defined once, although the bodies of extendedclass methods and procs can be defined again and again for interactive debugging. See the body and configbody commands for details.
Each namespace can have its own collection of objects and extendedclasses. The list of extendedclasses available in the current context can be queried using the "itcl::find extendedclasses" command, and the list of objects, with the "itcl::find objects" command.
A extendedclass can be deleted using the "delete extendedclass" command. Individual objects can be deleted using the "delete object" command.
The extendedclass definition is evaluated as a series of Tcl statements that define elements within the extendedclass. The following extendedclass definition commands are recognized:
The order of baseExtendedclass names in the inherit list affects the name resolution for extendedclass members. When the same member name appears in two or more base extendedclasses, the base extendedclass that appears first in the inherit list takes precedence. For example, if extendedclasses "Foo" and "Bar" both contain the member "x", and if another extendedclass has the "inherit" statement:
inherit Foo Bar
then the name "x" means "Foo::x". Other inherited members named "x" must be referenced with their explicit name, like "Bar::x".
Before the body is executed, the optional init statement is used to invoke any base extendedclass constructors that require arguments. Variables in the args specification can be accessed in the init code fragment, and passed to base extendedclass constructors. After evaluating the init statement, any base extendedclass constructors that have not been executed are invoked automatically without arguments. This ensures that all base extendedclasses are fully constructed before the constructor body is executed. By default, this scheme causes constructors to be invoked in order from least- to most-specific. This is exactly the opposite of the order that extendedclasses are reported by the info heritage command.
If construction is successful, the constructor always returns the object name-regardless of how the body is defined-and the object name becomes a command in the current namespace context. If construction fails, an error message is returned.
When an object is destroyed, all destructors in its extendedclass hierarchy are invoked in order from most- to least-specific. This is the order that the extendedclasses are reported by the "info heritage" command, and it is exactly the opposite of the default constructor order.
If the args list is specified, it establishes the usage information for this method. The body command can be used to redefine the method body, but the args list must match this specification.
Within the body of another extendedclass method, a method can be invoked like any other command-simply by using its name. Outside of the extendedclass context, the method name must be prefaced an object name, which provides the context for the data that it manipulates. Methods in a base extendedclass that are redefined in the current extendedclass, or hidden by another base extendedclass, can be qualified using the "extendedclassName::method" syntax.
If the args list is specified, it establishes the usage information for this proc. The body command can be used to redefine the proc body, but the args list must match this specification.
Within the body of another extendedclass method or proc, a proc can be invoked like any other command-simply by using its name. In any other namespace context, the proc is invoked using a qualified name like "extendedclassName::proc". Procs in a base extendedclass that are redefined in the current extendedclass, or hidden by another base extendedclass, can also be accessed via their qualified name.
If the optional init string is specified, it is used as the initial value of the variable when a new object is created. Initialization forces the variable to be a simple scalar value; uninitialized variables, on the other hand, can be set within the constructor and used as arrays.
The optional config script is only allowed for public variables. If specified, this code fragment is executed whenever a public variable is modified by the built-in "configure" method. The config script can also be specified outside of the extendedclass definition using the configbody command.
If the optional init string is specified, it is used as the initial value of the variable. Initialization forces the variable to be a simple scalar value; uninitialized variables, on the other hand, can be set with subsequent set and array commands and used as arrays.
Once a common data member has been defined, it can be set using set and array commands within the extendedclass definition. This allows common data members to be initialized as arrays. For example:
itcl::extendedclass Foo { common boolean set boolean(true) 1 set boolean(false) 0 }
Note that if common data members are initialized within the constructor, they get initialized again and again whenever new objects are created.
Once a extendedclass has been defined, the extendedclass name can be used as a command to create new objects belonging to the extendedclass.
If objName contains the string "#auto", that string is replaced with an automatically generated name. Names have the form extendedclassName<number>, where the extendedclassName part is modified to start with a lowercase letter. In extendedclass "Toaster", for example, the "#auto" specification would produce names like toaster0, toaster1, etc. Note that "#auto" can be also be buried within an object name:
fileselectiondialog .foo.bar.#auto -background red
This would generate an object named ".foo.bar.fileselectiondialog0".
Once an object has been created, the object name can be used as a command to invoke methods that operate on the object.
If a single option of the form "-varName" is specified, then this method returns the information for that one variable.
Otherwise, the arguments are treated as option/value pairs assigning new values to public variables. Each variable is assigned its new value, and if it has any "config" code associated with it, it is executed in the context of the extendedclass where it was defined. If the "config" code generates an error, the variable is set back to its previous value, and the configure method returns an error.
Sometimes a base extendedclass has a method or proc that is redefined with the same name in a derived extendedclass. This is a way of making the derived extendedclass handle the same operations as the base extendedclass, but with its own specialized behavior. For example, suppose we have a Toaster extendedclass that looks like this:
itcl::extendedclass Toaster { variable crumbs 0 method toast {nslices} { if {$crumbs > 50} { error "== FIRE! FIRE! ==" } set crumbs [expr $crumbs+4*$nslices] } method clean {} { set crumbs 0 } }
We might create another extendedclass like SmartToaster that redefines the "toast" method. If we want to access the base extendedclass method, we can qualify it with the base extendedclass name, to avoid ambiguity:
itcl::extendedclass SmartToaster { inherit Toaster method toast {nslices} { if {$crumbs > 40} { clean } return [Toaster::toast $nslices] } }
Instead of hard-coding the base extendedclass name, we can use the "chain" command like this:
itcl::extendedclass SmartToaster { inherit Toaster method toast {nslices} { if {$crumbs > 40} { clean } return [chain $nslices] } }
The chain command searches through the extendedclass hierarchy for a slightly more generic (base extendedclass) implementation of a method or proc, and invokes it with the specified arguments. It starts at the current extendedclass context and searches through base extendedclasses in the order that they are reported by the "info heritage" command. If another implementation is not found, this command does nothing and returns the null string.
Extendedclass definitions need not be loaded explicitly; they can be loaded as needed by the usual Tcl auto-loading facility. Each directory containing extendedclass definition files should have an accompanying "tclIndex" file. Each line in this file identifies a Tcl procedure or [incr Tcl] extendedclass definition and the file where the definition can be found.
For example, suppose a directory contains the definitions for extendedclasses "Toaster" and "SmartToaster". Then the "tclIndex" file for this directory would look like:
# Tcl autoload index file, version 2.0 for [incr Tcl] # This file is generated by the "auto_mkindex" command # and sourced to set up indexing information for one or # more commands. Typically each line is a command that # sets an element in the auto_index array, where the # element name is the name of a command and the value is # a script that loads the command. set auto_index(::Toaster) "source $dir/Toaster.itcl" set auto_index(::SmartToaster) "source $dir/SmartToaster.itcl"
The auto_mkindex command is used to automatically generate "tclIndex" files.
The auto-loader must be made aware of this directory by appending the directory name to the "auto_path" variable. When this is in place, extendedclasses will be auto-loaded as needed when used in an application.
C procedures can be integrated into an [incr Tcl] extendedclass definition to implement methods, procs, and the "config" code for public variables. Any body that starts with "@" is treated as the symbolic name for a C procedure.
Symbolic names are established by registering procedures via Itcl_RegisterC(). This is usually done in the Tcl_AppInit() procedure, which is automatically called when the interpreter starts up. In the following example, the procedure My_FooCmd() is registered with the symbolic name "foo". This procedure can be referenced in the body command as "@foo".
int Tcl_AppInit(interp) Tcl_Interp *interp; /* Interpreter for application. */ { if (Itcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } if (Itcl_RegisterC(interp, "foo", My_FooCmd) != TCL_OK) { return TCL_ERROR; } }
C procedures are implemented just like ordinary Tcl commands. See the CrtCommand man page for details. Within the procedure, extendedclass data members can be accessed like ordinary variables using Tcl_SetVar(), Tcl_GetVar(), Tcl_TraceVar(), etc. Extendedclass methods and procs can be executed like ordinary commands using Tcl_Eval(). [incr Tcl] makes this possible by automatically setting up the context before executing the C procedure.
This scheme provides a natural migration path for code development. Extendedclasses can be developed quickly using Tcl code to implement the bodies. An entire application can be built and tested. When necessary, individual bodies can be implemented with C code to improve performance.