I spent much of today chasing down an odd behavior with Tao. It passed all of my test scripts, but I ran into the most bizarre malfunction. I have a new behavior for “elements”, when they save the objects mark themselves as “delete me next trashday.”
The methods looks like this:
###
# Mark that this object should be deleted
# on the next pass of the garbage collector
#
# CAROSEL... RENEW RENEW
###
method carosel {} {
thanatos kiss $this
}
###
# Write the contentes of this node to the container's table
#
# This will automatically put the object on the carosel to
# be "renewed" on the next pass of the garbage collector
###
method renew {} {
$containerObj nodeSet $node_id [dict get [set $statevar] state]
carosel
}
Here’s what happened: instead of the node freeing itself, the CONTAINER freed itself. It took me a bit of coding, tapping out test cases, and whatnot to find that it was a bug in how I was manipulating the stack.
proc opop {} {
variable ostack
set handle [lindex $ostack 0]
set ostack [lrange $ostack 1 end]
set ::tao::topobject $handle
return $handle
}
Now this HAD worked for all of my test cases. The problem was none of my test cases called out to another object, and then continued on. I finally rewrote the opop proc to:
proc opop {} {
variable ostack
set handle [lindex $ostack 0]
set ostack [lrange $ostack 1 end]
set ::tao::topobject [lindex $ostack 0]
return $handle
}
The change is that clobjects now need to push themselves onto the stack. Before they used the ::tao::opoke call to make their presence known to the stack. (Not to mention imprint themselves on the top of every procedure.) As it is, I think the idea of calling a clobjects methods directly will be officially deprecated. From now on, use the ensemble.
While I was working on things, I have greatly simplified the structure of Containers, simplified garbage collection, and developed a more formal approach to method naming. “RecordLoad” and “RecordSave” have been replaced by “nodeGet” and “nodeSet”. (Not all nodes are records).
I have also GREATLY simplified the process of launching a node from a container. Before it was a hodge-podge of interactions directly between the container and the new node. No more. Now TDIF handles it all. It calls a new chain method “train” in the Container that takes the nodeId for the new node. train returns a dict with a complete configuration of the new object, suitable for passing to ::tao::object_create (i.e. it includes the class).
To feed data to child nodes, chain onto train. Remember that there is a variable named “result” that comes with the chain, and it is a dict containing the new state of the object. By default the first thing added to the new -objects dict is the complete memory of what values it holds from the container.