Version 8 of The ghosts of VB haunt this TCLer

Updated 2003-08-02 12:32:38

JMN 2003-08-02 The Ghosts of VB haunt this TCLer.

After a year or so of using TCL nearly every day - I've suddenly struck what feels like a mid-TCL-life crisis... I've actually caught myself pining for Visual Basic. Yes VB, that much-scoffed-at MicroSoft language, can actually be a very powerful creative environment; allowing you to focus on the problem at hand and to easily toss around complex structures much larger than can fit in a mere programmers head.

It may surprise some to learn that for many years it's been possible to write multithreaded VB applications with asynchronous calls and quite decent concurrency & performance for a serverside system supporting at least a couple of hundred LAN users. I get the impression sometimes that outsiders view it as some sort of glorified GUI builder. Such astoundingly hypocritical criticism coming from those using operating systems and scripting languages that have only in the past year (2003) or so (e.g FreeBSD, perl, TCL) even begun to catch up, in the area of threading, to the level that advanced VB users have come to assume as a given.

My reasons for 'leaving' VB were more political (open-source vs proprietary) and strategic (desire for multiplatform) than any feeling that the language itself may at some point put bounds on my programming creativity.

There's plenty that can be said both on the shortcomings and advantages of VB, TCl or any language for that matter - but my current mini-crisis of confidence in TCL is related fairly specifically to what might usually be called 'Object Oriented Programming'.

TCL suffers/enjoys, depending on your view or mood, from an array of different options for programming in a more or less 'Object Oriented' fashion. There are packages such as Snit, XOTcl, Stooop, ClassyTcl, itcl and various interesting object-like constructions in the wiki such as Chaining things.

I'll admit I've merely perused IncrTcl, and that of all the OO packages available, I've only actually written code using Snit & XOtcl. I've also played around with namespaces and my own perversion of Richard Suchenwirth's On things to get a feel for the basic mechanisms TCL alone offers in this regard.

While that is hardly a comprehensive investigation into the OOP options available for TCL - it's so far been disappointing and led me to peer back at my old VB code with more than a hint of wistfulness.

It's VB's power to organize your objects into a deep & wide custom hierarchy of object references that make it such a joy to work with.

Whilst OO enthusiasts may espouse the virtues of such complex OO concepts as inheritance (worse yet, multiple inheritance) & prototypes & mixins, the very straightforward aggregation and referencing supplied by VB, along with some IDE sugar in the form of dropdown statement completion, are IMHO the key to great deal of programmer freedom and productivity.

The freedom in particular comes from the ability to create object structures that echo your view of a portion of the problem, and then allow some of these structures to 'fade from the mind's working memory' safe in the knowledge that the IDE's dropdown hints, and the simple dot-separated object reference syntax, will help lead your mind back into the structure as necessary.

Though the VB OO world feels clean and generally simple to the programmer, it's not completely without pitfalls. One still has to worry about such things as forgotten circular references undesirably prolonging the lifetime of a set of linked objects for example; but by and large it's simple enough that the use of objects feels like a natural way to express your solutions and you don't find your thoughts on the problem at hand being interrupted too much by the technicalities of implementing it.

Now the drop-down 'method & object selection' of the IDE is nice sugar, but perhaps not entirely necessary; my feeling is that it's the unified delimiting syntax for accessing the object-hierarchy & methods that really keeps the object-system out of the way of my problem-solving thoughts.

Below is a rough example of the sort of things you can do with VB that I'm having trouble finding an analogous approach for in TCL. This code is incomplete and perhaps not syntactically 100% as I've had myself firmly ensconced in the TCL code for the past year or so, and my VB may be rusty. (Perhaps also my memories of what I didn't like about VB have faded..so my opinions here may be tainted a little by a case of those rose-coloured history-goggles looking back at the supposed 'good ol days' ;)


 'Enterprise is a variable referring to an instance of some kind of spacecraft class
 set Enterprise = New USSSpaceCraft
 Enterprise.nameOfCaptain = Kremen
 set Enterprise.warpdrive = new InfiniteImprobabilityDrive
 ' etc etc
 ' set various other properties.. some time elapses adventures are had..


 set SpacePort.dock1.SpaceShip = Enterprise
 set SpacePort.lastDocked = SpacePort.dock1.SpaceShip  

 set marvin = SpacePort.systems.maintenance.bots(1337)

 marvin.addToShipInspectionTasks(SpacePort.lastDocked)

 marvin.shiptasks("Enterprise").statusReport
 'marvin will of course want to tell us something bad, like the ship's main airlock probably won't want to open, and anyway he doesn't feel like telling us how to get a reference to the airlock object.
 'Luckily, we don't have to use marvin's reference to the ship, we can use any of various other paths to the ship object, so a little bit of hacking around on the station's VB-driven commandline will get the door open. 

'(no as far as I know MS hasn't really released a VB shell/commandline - but this spacestation has one anyway!)

 marvin.shiptasks("Enterprise").ship.airlock("main").open("sesame")
 set Enterprise = CollectionOfAllShipsThatMightDockHereOneDay("Enterprise")
 Enterprise.airlock("main").open("sesame")
 SpacePort.dock1.SpaceShip.airlock("main").open("sesame")
 SpacePort.lastDocked.airlock("main").open("sesame","please")
 'clunk

Now my frustration with the TCL OO world is that it appears to be difficult if not impossible to create such structures without winding up in a morass of command brackets or a rigid set of namespace trees that don't lend themselves to being pruned and rearranged and in any event, don't allow arguments to be passed to an item somewhere in the middle of the chain.

I can't even envisage what the TCL code would look like for a neat solution.. and I'm hoping that TCL's syntax itself is not the showstopper that will forever make such manipulations clumsy.

Let's try translating this line:

 marvin.shiptasks("Enterprise").ship.airlock("main").open("sesame")

into some hypothetical TCL OO system that may or may not currently exist. Would it be something like this?

 [[[marvin shiptasks "Enterprise"] ship] airlock "main"] open "sesame"

or this?

 marvin::shiptasks::Enterprise::ship::airlock::main open "sesame" 

We could of course break it down into lots of steps and hold variables for each object - but this would be a case of the mechanics of solving the problem interfering with the creative flow - and verbosity isn't normally a crime I'd expect of TCL.

In some ways the closest thing I've seen to a neat way of accessing a deep, malleable object hierarchy in TCL is the manipulation of XML using Tdom and xpath. See in particular Brian Theado's Natively accessing XML

This is however a case of using a syntax external to TCL (xpath) to perform the object-structure navigation - and it seems like a good solution for XML. Perhaps I'll have to go outside of TCL syntax and resort to some sort of string 'accessor' to get this kind of effect in a TCL OO situation.

I don't think I'm in real danger of migrating back to VB - as I've found a lot to love about TCL - but I'd really like to stop looking backwards with a sense of loss.

Please, if someone can demonstrate an idiom, using any of the myriad OO extensions available for TCL; for the sort of object referencing/aggregation & manipulation that VBers have enjoyed for so long, I'd be grateful.


Maybe you would feel more comfortable with a language like Python, which makes what you want to do very easy.


Joe Mistachkin Or you could do what I do and use TCLBridge to combine the best of both the Tcl/Tk and Visual Basic/COM worlds.


SLB are you looking for something like this:

   proc traverse {object args} {
      foreach arg $args {
         set object [eval {$object} $arg]
      }
      return $object
   }

   # VB marvin.shiptasks("Enterprise").ship.airlock("main").open("sesame") becomes Tcl:
   traverse $marvin {shiptasks Enterprise} ship {airlock main} {open sesame}

Well, tk widgets are objects. They are called with arguments. So if one were to create a similar environment for ships, one might have a series of commands to create objects ( usSpacecraft , tasks, airlock , ... ) and then call something like

   usSpacecraft .marvin -tasks [ship Enterprise -ship [airlock .main -open sesame]]

Your example syntax from above works ok with XOTcl (and nearly any reasonable Tcl OO system), you can even drop the quotes:

 [[[marvin shiptasks Enterprise] ship] airlock main] open sesame
     |          |        |         |       |     |     |     |
    Obj    instproc  argument      |       |     |     |     |
    -------------------------      |       |     |     |     |
              |                    |       |     |     |     |
             Obj              instproc     |     |     |     |
             ------------------------      |     |     |     |
                         |                 |     |     |     |
                        Obj          instproc   arg    |     |
                         -------------------------     |     |
                                      |                |     |
                                     Obj           instproc arg

For more comfort one could override unknown or use a convenience proc like traverse from above, but if the [ ... ] are ok, this simply works. And with XOTcl's sophisticated system you can change and rearrange the structure as you want, even on a per Object basis.


I think you miss the point - the original poster (OP) doesn't WANT to use the [...] notation...


GPS Here's a quick example I wrote of doing something like this with SDynObject. BTW SDynObject.tcl is 94 lines of Tcl code.

 source ./SDynObject.tcl
 #package require SDynObject works if you install it
 proc USSSpaceCraft obj {
  $obj model unknown
  #The user could have just done $obj model blah, but this is an example...
  sd.new.method set.model for $obj takes model {
   $self model $model
  }
  sd.new.method get.model for $obj takes {} {
   return [$self model]
  }
  return $obj
 }

 proc InfiniteImprobabilityDrive obj {
  $obj warp 0
  $obj maxWarp 0
  sd.new.method goto.warp.n for $obj takes n {
   if {$n > [$self maxWarp]} {
    puts "warp $n is beyond this engines capabilities (ask Scotty)"
    return
   }

   if {[$self warp] < $n} {
    puts "Increasing to warp $n..."
   } else {
    puts "Decreasing to warp $n..."
   }
   $self warp $n
  } 
  return $obj
 }

 proc main {} {
  set Enterprise [sd.new.object]

  USSSpaceCraft $Enterprise
  $Enterprise->set.model "NC-95343"
  $Enterprise nameOfCaptain Kremin
  $Enterprise warpDrive [InfiniteImprobabilityDrive [sd.new.object]]

  [$Enterprise warpDrive] model 350
  [$Enterprise warpDrive] maxWarp 10

  puts "Ship is [$Enterprise->get.model]"
  [$Enterprise warpDrive]->goto.warp.n 1
  #We're going fast.
  [$Enterprise warpDrive]->goto.warp.n 6
  #I'm feeling queezy.  Slow down young whippersnapper...
  [$Enterprise warpDrive]->goto.warp.n 2
  #Klingons are attacking...
  [$Enterprise warpDrive]->goto.warp.n 12
 }
 main

Example output: $ tclsh84s.exe Enterprise.tcl Ship is NC-95343 Increasing to warp 1... Increasing to warp 6... Decreasing to warp 2... warp 12 is beyond this engines capabilities (ask Scotty)

Oh, and one last thing. If you want to refer to the warpDrive without using brackets you simply do:

 set warpDrive [$Enterprise warpDrive]

and then:

 $warpDrive->goto.warp.n 5

Category Object Orientation