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.
MJ: Won't this lead to problems if you define commands with the same names as Itcl commands in the global namespace? In that case namespace unknown will not trigger.
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.
DKF: This is like Java's class methods? If so, try this:
DKF: I'm thinking that this would perhaps be better better done through a custom method type. One of the key things I did with TclOO is to provide a general method implementation system, allowing many different implementations to be used within a single framework. As far as I'm aware, this is quite different to how Tcl-based OO systems have worked in the past. Maybe I'm wrong (it depends on whether the protection applies to the method implementation or to the interface) but in that case I'd need to understand exactly what is going on.
As a side note, it has been my policy in TclOO to make non-callable methods invisible (except through my) as opposed to throwing errors when you try to call them.
APW 2007-06-10 - Throwing errors where calling non-callable methods is exactly what Itcl expects. :;)
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.
DKF: This feels very much like something best achieved through custom method types. All this stuff can be controlled easily at that level.
APW 2007-06-10 - But then I will also need an own InvokeProcedureMethod function, so most of the method handling is the done without tclOO :-( .
APW 2007-06-09 - @DKF: after spending some thoughts on your answers I have the feeling there will not much I can use directly from tclOO. Using custom method types, I will need my own InvokeProcedureMethod and then I can directly pass all the needed data via clientData to my InvokeProcedureMethod. So there will be no further need to use the metadata mechanism, as that would be more overhead to call it. For the info stuff I will nevertheless need my own code, as it is so different to tclOO info. For constructors and destructors - as you suggested - I will need my own code. To handle protection violation - as you suggested - I will need my own code. So what I can use from tclOO would mostly be creation, administration and deletion of classes and objects. I cannot use tclOOCall.c, because I need additional information (and the special code to provide in there the checking of protection violation), I will not need tclOODefineCmds.c, as I directly call the tclOO API functions, I will not need tclOOInfo.c (see above). That was not my intention! I would like to use much more of it! I like the implementation of tclOOCall.c, but at least for Itcl (maybe also for others) it is too limited at the moment. Do you have any better ideas?
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 ]