TclOO 1.0 Released edit
TclOO 1.0 was released on 2012-12-21. It corresponds to the version included as part of Tcl 8.6.0. Download
.TclOO 0.6 Released edit
TclOO 0.6 has been released on 2008-10-14. It corresponds to the version included as part of Tcl 8.6a3.Announcement edit
Announcement on news:comp.lang.tcl
on 01-Oct-2007:I'm very pleased to announce that TclOO version 0.1 is now released. It's hosted in the Tcl project at SourceForge, so you can download the source package from: http://sf.net/project/showfiles.php?group_id=10894&package_id=247402
It requires Tcl 8.5b1 to build and operate; see the enclosed README.txt for details on how to build this TEA-based package. No promises on whether I'll do a binary package for any platforms as yet. :-)Details about this package can be found in the Wiki, naturally, at http://wiki.tcl.tk/TclOO
and any problems should be reported using Tcl's issue trackers at http://sf.net/tracker/?group_id=10894&atid=110894
with the summary field prefixed by "TclOO:".SDW: For those of you following at home, TclOO is now in the Teacup package manager (thanks Jeff!). If you have ActiveTcl 8.5 beta 9 or greater run: teacup install TclOO, and try it out for yourself.RS tried, and failed at first attempt - needed teacup proxy proxyname port before, then it worked. For the impatient, here's the simple example from README.txt (which by the way does not come with the installed package, but can be found on http://tcl.cvs.sourceforge.net/tcl/oocore/
).DKF: If you're checking it out of CVS, remember to check out oo and not oocore so that you pick up tclconfig in the right directory.LV: Has anyone written a Tutorial for the specfics of TclOO?package require TclOO; #if loading for the first time
oo::class create summation {
constructor {} {
variable v 0
}
method add x {
variable v
incr v $x
}
method value {} {
variable v
return $v
}
destructor {
variable v
puts "Ended with value $v"
}
}
set sum [summation new]
puts "Start with [$sum value]"
for {set i 1} {$i <= 10} {incr i} {
puts "Add $i to get [$sum add $i]"
}
summation destroywhich gives (only last lines shown):... Add 10 to get 55 % summation destroy Ended with value 55Should you see the error message
attempt to provide package TclOO 0.1.1 failed: package TclOO 0.1 provided insteadit helps to refetch the HEAD, rerun configure, and do a clean build. The test suite is at http://tcl.cvs.sourceforge.net/tcl/oocore/tests/oo.test
and passes well on my Win XP/8.5b1 setup.Update: Without teacup, I took the source distro http://downloads.sourceforge.net/tcl/TclOO0.1.tar.gz?modtime=1191249015&big_mirror=1
which falied to make. Following tclguy's advice, I obtained http://tcl.cvs.sourceforge.net/tcl/oocore/TclOO.rc
, created a win directory in the sources and put it there, and almost presto... TclOO runs on old W95 too (at least passes all 85 tests in oo.test :^)What Is TclOO? edit
LV 2007 Oct 01: So what is the intention for TclOO? Is the intention that people will write Tcl object oriented code with this extension? Or is it intended to be a framework for existing and future OO extensions to be more powerful?DKF: It's a core for other OO extensions, but in order to do that job properly it also needs to be a basic OO framework itself.DKF: The other thing that it isn't is a class library. That can go in tcllib just nicely.LV 2008-05-29: So, for J. Casual Tcl User, what are the ramifications of the distinguishment of being a core for OO, and not being a class library? What will one see (and not see) compared to the normal Tcl OO extension?DKF: I'm not really sure how to respond to that. The key consequence is probably that not much will change; you'll be able to ignore the fact that there is OO support except when it is providing a specific benefit to you. At an implementation level, the benefit is that it scopes the development and keeps the amount of work required sane and the delivery schedule practical. You might or might not think of this as a benefit... :-)LV I guess what I mean is this - when J Average Tcl developer, used to using Snit, stooop, XOTcl, itcl, etc. sees the annoucement that Tcl 8.6 now has OO support in the core, the expectation will be that now there is the one ring to bind them all - that these new commands will be sufficiently enough commands for J Average Tcl developer to use for all their OO needs.However, it seems to me, reading comments to date here and elsewhere, that developers trying to use only ::tcl::oo to do their work may find that it is doable, but limited compared to what they are used to seeing in snit, incr tcl, and the other extensions. Am I correct in this understanding? From the beginning, I thought this code was really designed to be used by the OO extension writers. But I keep seeing remarks around the community as if people are expecting that oo in the core means something that, in my mind, is much more grandiose than is planned. I'm just trying to determine whether my expectations are too low, or others have expectations a bit too high.DKF: Ah. Well, I think we'll be doing some more classes (e.g. quite possibly code to support chan create better, maybe a megawidget framework, and TDBC of course) but there won't be a vast number. We don't need to change the whole world; Tcl was working fairly well beforehand.Discussion edit
DKF 18 May 2007: At last, after a long hiatus, I've had enough time to finish getting the code smashed into shape as a loadable TEA extension. It works for me (as in: successfully runs the test suite) on both Windows and Linux (built with gcc on both) as long as you're using a recent-enough version of Tcl (i.e. more recent than 8.5a6; there was an internal API that had to be modified to prevent crashes when info frame was used inside a method). Right now, there's no distribution, but you can check it out of cvs using:cvs -d:pserver:anonymous@tcl.cvs.sourceforge.net:/cvsroot/tcl co ooTo build, just change into the base directory of the code and do a configure/make combo.(Also includes experimental support for building a starkit version, as long as you have sdx on the path. Let me know if it works or not, as it doesn't work locally for other ugly reasons.)Note - do not check out the oocore module; that's incomplete since it lacks the (required) TEA build support.04jun07 jcw - Some notes on trying to build this extension:
- I'm used to doing just "make install", but that only works if "make install" also causes a normal "make"
- am getting the following build error (MacOSX x86):
install: /.../TclOO-0.1/library/*.tcl: No such file or directory
- have worked around it by creating an empty library/blah.tcl for now :)
my variable {*}[info vars [namespace current]::*]IOW, set up methods to automatically have access to all object state as plain variables (as in Itcl). The above line would be added in front of all method definitions, using a small wrapper (am generating methods dynamically anyway).This assumes that all variables are defined in the constructor.escargo Does this use of variable contrast confusingly with the Tcl variable where something like that would assign the names of half the variables as the values of the other half of the variables?jcw - Well, I'm just trying it out, so don't shoot me ;) - although so far I tend prefer this over the "variable" cmd.escargo - I was just asking a question. It's just that having my variable work not like variable might be considered confusing.jcw - Here's an example with some output which may help those who don't have TclOO yet:oo::class create dog {
method a {} {
puts a1-[namespace current]
puts a2-[namespace path]
foreach x [namespace path] {
puts a3-$x-[info commands ${x}::*]
}
puts a4-[info vars [namespace current]::*]
my variable e
set e f
puts a5-[info vars [namespace current]::*]
}
self.method b {} {
puts b1-[namespace current]
puts b2-[namespace path]
foreach x [namespace path] {
puts b3-$x-[info commands ${x}::*]
}
puts b4-[info vars [namespace current]::*]
my variable e
set e f
puts b5-[info vars [namespace current]::*]
}
}
dog create fifi
fifi a
dog b
# Output:
# a1-::oo::Obj4
# a2-::oo::Helpers
# a3-::oo::Helpers-::oo::Helpers::self ::oo::Helpers::next
# a4-
# a5-::oo::Obj4::e
# b1-::oo::Obj3
# b2-::oo::Helpers ::oo
# b3-::oo::Helpers-::oo::Helpers::self ::oo::Helpers::next
# b3-::oo-::oo::InfoClass ::oo::class ::oo::InfoObject ::oo::object \
# ::oo::copy ::oo::define
# b4-
# b5-::oo::Obj3::eAs you can see, each class and each instance gets its own namespace. Note also that class Dog ended up as namespace Obj3, even though it was constructed with a specific name (which is not necessarily globally unique, though).DKF: I've been experimenting for a while now with OO systems, and a my variable that brings every variable in the object into scope is probably not what you want as it causes great problems in subclasses (i.e. clashes between subclasses' variables and local variables). Instead, I think that being able to pick up all the variables defined within a particular class would be far more useful. OTOH, it's not at all trivial to implement (I think I expose enough API that it can be done through the use of class metadata, but I'm not certain) so I'm not in a hurry to change things.It was a deliberate decision to make my variable different from variable; the latter has syntax that is almost never what anyone wants, and so is a priori suboptimal. Hence I went for something that was more likely to be what you need. :-)(escargo - Well, I wondered if you did it on purpose, and you did. And I see it was for what you think is a good reason.)Also, as noted, the internal namespaces have names that are not necessarily those of the created object, and their names are deliberately not documented (i.e. they could change between point releases with no warning). Use the introspection facilities to go from one to the other.APW 2007-06-05 @ jcw: I am working on an extended version of dkf's code suitable for Itcl, which would have solutions for some of the problems you have mentioned above. For example I am using "apply" and "namespace upvar" and "namespace unknown" to generate Itcl methods, which have access to all the class variables in the class hierarchy (if they are not private) etc. Using only the name of a variable as in Itcl is possible, same for call of Itcl methods without the "my" in front. If you are interested please contact me directly, the implementation is not yet ready for real testing.@ dkf: If I know what I really need additionally for Itcl I will contact you and we can try to perhaps get a merged version. At the moment all my modifications are additional functionality so that the original functionality should work as before with also running all your tests without problems.Aspects with TclOO edit
DKF: The following example is ripped from the documentation of next: oo::class create cache {
filter Memoize
method Memoize args {
# Do not filter the core method implementations
if {[lindex [self target] 0] eq "::oo::object"} {
return [next {*}$args]
}
# Check if the value is already in the cache
my variable ValueCache
set key [self target],$args
if {[info exist ValueCache($key)]} {
return $ValueCache($key)
}
# Compute value, insert into cache, and return it
return [set ValueCache($key) [next {*}$args]]
}
method flushCache {} {
my variable ValueCache
unset ValueCache
# Skip the cacheing
return -level 2 ""
}
}
oo::object create demo
oo::define demo {
mixin cache
method compute {a b c} {
after 3000 ;# Simulate deep thought
return [expr {$a + $b * $c}]
}
method compute2 {a b c} {
after 3000 ;# Simulate deep thought
return [expr {$a * $b + $c}]
}
} puts [demo compute 1 2 3] → prints "7" after delay
puts [demo compute2 4 5 6] → prints "26" after delay
puts [demo compute 1 2 3] → prints "7" instantly
puts [demo compute2 4 5 6] → prints "26" instantly
puts [demo compute 4 5 6] → prints "34" after delay
puts [demo compute 4 5 6] → prints "34" instantly
puts [demo compute 1 2 3] → prints "7" instantly
demo flushCache
puts [demo compute 1 2 3] → prints "7" after delayWay cool, great separation of functionality. Next step: a Metakit backed cache? ;) -jcwDKF: I've thought more about this, and have written an Aspect Support Class for TclOO.APW 2007-06-06 For discussion of Itcl related topics for a new implementation based on this TIP see tclOO missing features for Itcl
Performance Measurement edit
DKF 20-Sept-2007: As seen in my Tck2k7 paper, TclOO is really quite fast. Here's those performance figures (correct with 8.5b1 on my ancient laptop).| OO System | Objects Made (s⁻¹) | Method Calls (s⁻¹) |
|---|---|---|
| TclOO 0.1 | 32800 | 206000 |
| itcl 3.4.0 | 22500 | 128000 |
| XOTcl 1.5.5 | 18500 | 87500 |
| Snit 2.1 | 2080 | 54700 |
| Snit 1.2 | 1020 | 24700 |
| stooop 4.4.1 | 13900 | 26700 |
| OO System | Objects Made (s⁻¹) | Method Calls (s⁻¹) |
|---|---|---|
| TclOO 0.3 | 121000 | 981000 |
| itcl 3.4.0 | 87900 | 573000 |
| XOTcl 1.6.0 | 87200 | 404000 |
| Snit 2.2.1 | 7190 | 881000 |
The script used to create the performance data is below. (Well, I actually did it interactively over a few runs, so I don't warrant that this script will really work...)
Performance Analysis Script
package require Tcl 8.5b1 # Compute Calls Per Second of a script # Note that this script is self-tuning; it prefers to execute a script for around a second
proc cps {script} {
# Eat the script compilation costs
uplevel 1 [list time $script]
# Have a guess at how many iterations to run for around a second
set s [uplevel 1 [list time $script 5]]
set iters [expr {round(1/([lindex $s 0]/1e6))}]
if {$iters < 50} {
puts "WARNING: number of iterations low"
}
# The main timing run
set s [uplevel 1 [list time $script $iters]]
set cps [expr {round(1/([lindex $s 0]/1e6))}]
puts "$cps calls per second of: $script"
}#────────────────────────────────────────────────────────────────────────── puts "using Itcl..." package require Itcl 3.4 namespace path itcl
class foo {
variable x
constructor {} {
set x 1
}
method bar {} {
set x [expr {!$x}]
}
}
foo f
cps {f bar}
delete object f
cps {delete object [foo f]}
delete class foo#────────────────────────────────────────────────────────────────────────── puts "using XOTcl..." package require XOTcl 1.5.5 namespace path xotcl
Class create Foo
Foo parameter x
Foo instproc init {} {
my set x 1
}
Foo instproc bar {} {
my instvar x
set x [expr {!$x}]
}
Foo create f
cps {f bar}
f destroy
cps {[Foo create f] destroy}
Foo destroy#────────────────────────────────────────────────────────────────────────── puts "using TclOO..." package require TclOO 0.1 namespace path oo
class create foo {
constructor {} {
variable x 1
}
method bar {} {
variable x
set x [expr {!$x}]
}
}
foo create f
cps {f bar}
f destroy
cps {[foo create f] destroy}
foo destroy#────────────────────────────────────────────────────────────────────────── puts "using snit..." package require snit 2.1
snit::type foo {
variable x
constructor {} {
set x 1
}
method foo {} {
set x [expr {!$x}]
}
}
foo f
cps {f bar}
f destroy
cps {[foo f] destroy}
foo destroy#────────────────────────────────────────────────────────────────────────── puts "using stooop..." # Must go last because it plays games with proc which might disturb the # performance of other OO systems. Note that stooop has both virtual and # non-virtual methods, with very different performance profiles. The virtual # ones are much more comparable in capability to other OO systems... package require stooop 4.4.1 namespace path stooop
class foo {
proc foo {this} {
set ($this,x) 1
}
proc ~foo {this} {}
virtual proc bar {this} {
set ($this,x) [expr {!$($this,x)}]
}
proc bar-nv {this} {
set ($this,x) [expr {!$($this,x)}]
}
}
set f [new foo]
cps {$f bar}
cps {$f bar-nv}
delete $f
cps {delete [new foo]}Examples edit
- Playing with TclOO
- TclOO Tricks
- TclOO Channels
- coroutine
- contains a TclOO example by CMcC
See Also edit
- TIP #257: Object Orientation for Tcl
- Megawidgets with TclOO
- Fun with TclOO, coroutines and apply
- TclOO Method Dispatch
- Serializing TclOO objects
- typedlist
- TclOO trace filter
- MeTOO – MeTOO emulates TclOO for Tcl 8.4
- TclOO Tutorial
- JBR's tcloo.tcl
- oo::class [1]
- oo::copy [2]
- oo::define [3]
- oo::objdefine [4]
- oo::object [5]
- my [6]
- next [7]
- self [8]
- info [9]
- info class provides introspection of classes (many subcommands)
- info object provides introspection of objects (many subcommands)

