APW 2007-06-06 Some time ago I started efforts to reimplement Itcl on top of tclOO [L1 ]. I started based on tclOO, using only the API functions of tclOO and a lot of additonal code in C. With that approach I had about 90% of the test suite of Itcl running successfully, but I saw, after all that, I was only using a small part of tclOO code.
My second approach was implementing a TMOS-like [L2 ] extension using a lot of code from the XOTcl reference implementation and again achieved about 90% of the test suite of Itcl running successfully. I felt that the code was too big and too complicated, partially because of having all these XOTcl features running. Additionally there were some features of Itcl which would have needed a lot of redesign of that code to pass the Itcl test suite.
So I decided to come back to the tclOO implementation, thinking that it is, after all, the best starting point. This time I changed/extended the tclOO code directly so as to be able to use as much as possible of that code, because I had the feeling it has a lot of good implemented features, which I did like to use. I also did like the implementation of the dispatch and class/object creation mechanism much more than the one in the TMOS implementation.
I started implementing extensions to tclOO (directly in tclOO, as the API is not enough) to get a lot of features of Itcl to run. This includes a lot of code implemented in pure-Tcl on top of tclOO. Doing that, I learned a lot more details and "specialities" about Itcl.
Currently I have an implementation which is successfully running about 70% of the Itcl test suite.
Having now a better feeling about what is needed for Itcl, I will start to write down the missing tclOO features and my solutions for them, in the hope that there will be some comments (especially from dkf). These comments could also include suggestions on how to solve the problem in a different way, without having to modify tclOO.
In the following, solution means that is my current (not always optimal) solution for the problem.
In the code examples I am using a meta syntax, not the Itcl or tclOO syntax, to make the code shorter!
Here starts the list; I will add topics as they come up:
DKF: This is actually a serious problem, since the current design of the system specifically decouples the namespace and the class (i.e., object) name.
DKF: Good solution.
DKF: implement the self variable by prepending each method body with:
set self [self]
class foo { constructor {args} { puts foo } } class bar { constructor {args} { puts bar } } class foobar { superclass foo bar constructor {args} { puts foobar } } class geek { constructor {args} { puts geek } } class mongrel { superclass foobar geek constructor {args} { puts mongrel } } output: geek bar foo foobar mongrel
In other words Itcl walks through the list of superclasses starting at the end based on the definition order. It looks for inherited classes up to the root class and unrolls the built stack. Then for the next class in inheritance, the same is done.
DKF: The [next] command, if put first, causes the constructors to be walked in the desired order.
% package req TclOO; namespace path oo % class create foo { constructor {} {next; puts foo} } ::foo % class create bar { constructor {} {next; puts bar} } ::bar % class create foobar { superclass foo bar; constructor {} {next; puts foobar}} ::foobar % class create geek {constructor {} {next; puts geek}} ::geek % class create mongrel {superclass foobar geek; constructor {} {next; puts mongrel}} ::mongrel % [mongrel new] destroy geek bar foo foobar mongrel
DKF: Discussion seems to indicate that there is a deeper problem here, but not one I understand yet.
APW: I need info class superclasses ... on a lot of places for Itcl and it returns the class names not in the order the have been defined, so I am calling
class create mongrel {superclass geek foobar; constructor {} {next; puts mongrel}}
to get the order as expected in Itcl, for the Itcl input:
itcl::class mongrel { inherit foobar geek; constructor {} {puts mongrel}}
The script after the arguments and before the body is the "constructor init code" class foo { constructor {args} { puts foo } } class bar { constructor {args} { puts bar } } class foobar { superclass foo bar constructor {args} { foo::constructor ; # this is the init code which calls the constructor of class foo } { puts foobar } } class geek { constructor {args} { puts geek } } class mongrel { superclass foobar geek constructor {args} { foobar::constructor } { puts mongrel } } output: foo bar foobar geek mongrel
DKF: Definitely sounds like you need a custom constructor command. It might even be easier to not use TclOO constructors at all and instead define your own scheme using multiple methods (this is what you'd have to do if doing XOTcl on top of TclOO).
DKF: I thought about having abstract methods - early drafts had it in - but in the end I took it out. I reasoned that it would be easier to implement such things on top of a basic core than it would be to figure out how to do it directly.
DKF: I think this sort of thing should be fairly simple to hang off the metadata mechanism.
if (tobjPtr->selfClsPtr->thisPtr->namespacePtr != NULL) { /* use the classes namespace if it exists for example for Itcl */ namespacePtr = tobjPtr->selfClsPtr->thisPtr->namespacePtr; } else { namespacePtr = tobjPtr->namespacePtr; }
The variables of the different classes are mapped (if accessable) using the "namespace upvar" command (that code is inserted in the body of a method at the very beginning), when the class is completely parsed. The path for that "namespace upvar" command is handled using the self variable in the method parameters (see above). This allows the methods to be compiled once only for performance on the very first call to a class method.
APW I would feel happy if native english speakers could correct the wording and the grammar above where necessary.
escargo - I think it might be clearer if instead of mixing bullets and definition lists, the text that is currently part of the bullet was at the beginning of the text after problem (maybe in bold face or italic to set it off). That's too radical a chance for me to make without checking for other opinions first. I think the list would also take up less space on the page.
APW You are right, I am also not happy with the layout, but it was the best, which I was able to produce. If someone knows better please go ahead. Have changed a little bit, but don't know a method to get the text behind "problem:" instead of the next line.
escargo - I stuck in some horizontal rules to make the problem - solution pairs more obvious, but I think the result looks much better.
APW Yes indeed!
jcw - I changed the last example, maybe you like that better - else, just restore it, please :)
APW - Thanks jcw, I have added another tag, maybe that's a better solution to what I had in mind.
[ Category Discussion | Category Itcl | Category Object Orientation ]