**More on object-oriented programming** !!!!!! '''[Tcl Tutorial Lesson OOP1%|%Previous lesson%|%]''' | '''[Tcl Tutorial Index%|%Index%|%]''' !!!!!! Object-oriented programming is in fact a vast topic and each programming language that supports it puts its own emphasis on particular aspects. With Tcl you might say that it puts particular emphasis on objects being dynamic entities, just like the rest of Tcl. For one thing, an object or a class may choose to ''export'' a method or ''unexport'' it. The rule that is used by default is: * If the method's name starts with an upper case letter it is private. * If the method's name starts with a lower case letter it is public. But at any time you may change that: ====== # Print is private by default ... oo::define myclass method Print {} { puts "This is the state of the object: ... (print variables)" } myclass create myobj # Export it just for this object oo::objdefine myobj { export Print } myobj Print ====== Objects continue to exist, unless you explicitly destroy them - in that respect they behave as builtin commands and procedures and not as variables. To destroy an object, call its `destroy` method - either the default, automatically constructed, method or the destructor defined for the class/object: ====== myobj destroy ====== Trying to print the state of this object or do anything else with it after it has been destroyed would result in an error: ====== % myobj Print invalid command name "myobj" while executing "myobj Print" ====== Extending classes can be done in various ways: * Defining new methods after the creation of the class, using the `::oo::define` command * Inheritance - create a new class based on one or more existing classes * Defining mixin classes - the methods of such a class become available in the original class For example, you could define a class that prints out the data members of the object and then mix it into the definition of another class: ====== oo::class create printable { method print {} { foreach v [info class variables [info object class [self]]] { my variable $v puts "$v: [set $v]" } } } oo::class create counter { variable count constructor {} { set count 0 } method incr {} { incr count } mixin printable } counter create countup countup incr countup incr countup print ====== which prints, as expected: ====== count: 2 ====== In the above fragment we use several introspection features for interrogating the object and the class it belongs to. There are many more facilities available - see the [http://www.magicsplat.com/articles/oo.html%|%online chapter%|%] of Ashok's book. Yet another feature to influence the behaviour of an object or a class of objects is the use of filters. Basically it is a method that is called before the actual method that you want to call. A simple example is this: to track down where a particular object is being used, you introduce a filter method: ====== oo::objdefine countup { method Log args { my variable count puts "Called in [lindex [info level 1] 0] ... counter was: $count" return [next {*}$args] } filter Log } proc runCalculation {} { ::countup incr ::countup incr puts "Done" } runCalculation ====== gives: ====== count: 2 Called in runCalculation ... counter was: 2 Called in runCalculation ... counter was: 3 Done ====== The `next` command makes it possible to delegate the work to the next method in a potentially long chain of commands. Just make sure that next command has all the arguments it needs. (''Note:'' we look at level 1, not level 0, to get to the caller of the `count` method of `countup`) With these and other facilities at hand you can build a program that takes advantage of well-known object-oriented programming techniques as well the dynamic character of Tcl. The main pitfall is that you make it too sophisticated, so that it becomes increasingly difficult to understand what is going on. On the other hand, mixins and filters make it possible to trace the use of the objects through your program. !!!!!! '''[Tcl Tutorial Lesson 43%|%Previous lesson%|%]''' | '''[Tcl Tutorial Index%|%Index%|%]''' !!!!!!