'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 XMLThis 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.jmn Yes, I think maybe I would be comfortable with Python, but I'm also in general comfortable with TCL . This page owes a little of its inspiration to pages such as Things holding Tcl back , Tcl Advocacy & About Tcl and popularity - It's my current commitment to Tcl and its use to solve my problems that leads me to examine how TCL appears to an ex-VB user. Of course I can't speak for ex-VBers in general, and in fact I'd be quite interested to hear from other TCLers who once used VB for their opinions on the migration process, and what they feel they've lost and gained. I love TCL - but at this stage I simply couldn't look a VB user in the eye and say that a year or so on into their TCL usage - they'll be equally or more productive. Considering TCL's inherent simplicity - this came as a bit of a shock to me. I suspect TCL may be missing out on the opportunity to cultivate a lot of VB users looking to make a change... maybe they are all going to Python.
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.jmn If it was the COM side of things that I was particularly missing, this might have been a useful approach for some situation. While I think the ability to easily call your object models across process boundaries is a great plus - at this stage I'm concerned more with manipulation of local data structures, and for this I think a mixture of TCL & VB is not a hybrid that will help at all in simplifying things.
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}jmn This looks promising. I'll have to play around with it and see what can be done with it.
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]]jmn This doesn't look good to me at all. While it may work for GUI systems where over time one learns the particular options and idioms for certain widgets, I think this syntax would be somewhat intrusive and unintuitive for dynamic object structures.
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 argFor 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.jmn Despite my comments above re inheritance & mixins, I do actually find XOTcl quite nice in this regard. It does seem to give a lot of flexibility. I'll have a go at putting a 'traverse' wrapper over it in some way, but to date I've found XOTcl to be a bit more mental work than I'd like. I don't expect everything to be simple, but the simple things should be simple to build as it were..
I think you miss the point - the original poster (OP) doesn't WANT to use the [...] notation...jmn That's right. I wouldn't want people to think I'm in any way railing against TCL syntax, in fact for most things I find it just fine. For navigating objects however, I'd like to be able to start a command line not knowing how deep in the structure I'm about to go, and move left to right without the need to regress and fill in the left brackets. It may seem a trivial requirement - but it's my argument that it's more intrusive than one might think, and when you're trying to quickly throw down a bunch of lines, having to go back and count brackets is a drain on the stream-of-thought that can result in ideas falling out of my overtaxed little mind.
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 engine's 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 } mainExample 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 engine's 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 5jmn This syntax too looks reasonable - but it's not clear to me yet how it'll help for deeper traversals into an object reference hierarchy. Setting variables for everything on the left prior to the final method is sometimes ok - but is other times as disruptive as bracket-counting.One might think my apparent aversion to bracket-counting would mean that functional languages leave me cold - but in fact I'm also quite a fan of ErlangThanks for all the responses so far - it's given me a bit more to investigate and think about.
Jacob Levy August 02, 2003: If you dont mind typing one extra word, you can have your VB cake and stay in Tcl too :) I modified SLB's code slightly to make it even more VB'ish:
proc VB {cascade} { set args [split $cascade .] set object [lindex $args 0] set args [lrange $args 1 end] foreach arg $args { set object [eval {$object} [split $arg ()]] } return $object } # VB marvin.shiptasks("Enterprise").ship.airlock("main").open("sesame") becomes Tcl: VB $marvin.shiptasks(Enterprise).ship.airlock(main).open(sesame)Note that I didnt test this actually :)jmn 2003-08-04 This approach is what I meant above by a string 'accessor'. Looks like it might be good for a [Playing VB] page :)SLB The use of split is fine for simple examples, but could cause problems if you extend things a little. For example:
set ship "U.S.S. Enterprise" VB $marvin.shiptasks($ship).ship.airlock(main).open(sesame)The 'split' is going to break up $ship. Seems to me, you'd need some quite fancy parsing to make this approach robust enough to handle arbitrary strings as arguments.
This page spawned a small package to give me some of what I'm after: objectwalker