SDynObject

See below for more information about SDynObject.

GPS: This project has been removed from the public server. I never received any positive comments that I can recall, so it's gone. Feel free to remove this page.


JMN Getting attention and feedback for yet another TCL OO system is always going to be an uphill battle. The lack of a standard OO system for TCL, and the relative ease of hacking together an OO system in plain TCL means that numerous offerings have sprung to life in this area. Heck, I'm even evolving one myself.

Even so, your apparent tentative wikiSuicide http://c2.com/cgi/wiki?WikiSuicide (notwithstanding your backwards denial) strikes me as proof you are simply incapable of judging the value of your own contributions. Let me give you a hand here - if you find it interesting George, I feel bold enough to claim a reasonable slice of the TCL community will also find it interesting. I've browsed through and played with some of your projects (e.g grindweb, 3dobjects) more than once and whilst there were some things you were doing I didn't quite understand - it was a nice body of work and I was glad for it's existence.

That said however, I'm annoyed that you feel your contributions should require active positive reinforcement to keep them alive. There's far too much material out there for everyone to be patting everyone on the back at every turn and holding hands. By wiping your material in this apparently petty phase of personal fragility you reduce the value of your future contributions - because people don't know if the rug is going to be yanked out from under them. When you make your material publically available - sure it's a generous selfless act of sharing - but you're also competing in an information overloaded world for the precious resource of other peoples consideration & attention span. It's nice to think that if a particular project has been presented for us to invest some thought in, that even if the original author ceases development, the code may remain publically available for someone else to pick up and run with or even just as a comparison as an alternative way of doing something.

You're not the only one to go through periods of self-doubt and/or disillusionment with the sometimes hollow & lonely pursuit of coding and experimentation - but the rewards are I suspect mainly in the activity itself - and any spinoffs in the form of obvious peer-recognition and/or job opportunities may not materialise til well down the track for even the very talented. Many valuable contributions to the community go unapplauded.

Even though I probably haven't given so much as a "that's cool" piece of feedback to you; I think I shouldn't have to, even though I've not made a fraction of the contributions you have - and I feel somewhat betrayed by the reversal of the spirit of sharing that you originally had. Please put your stuff back.

George Peter Staplin: Julian, I respect what you say. So, I have restored the old page here. I have a tarball of all my old projects, and I may make it public again.


SDynObject is a dynamic object-oriented (OO) system. It features multiple inheritance, fast execution, and simplicity.

Most OO systems have a class command. In SDynObject we don't need such a thing, because proc provides all that we need. For example:

 proc Bat obj {
  sd.new.method hit.ball for $obj takes ball {
   #at this point we have ball passed to us.
  }
  return $obj
 }

Note: It isn't necessary to use . in the name of a method. I like using . rather than _ or : because it takes only one keystroke instead of two.

How would we use the class given above you may ask? Well, it's really quite easy. First we need to create an object and then we pass the object to the Bat proc so that it inherits hit.ball. For example:

 set b [Bat [sd.new.object]]
 $b->hit.ball someball

The $b->hit.ball command is just a normal Tcl procedure.

If you wanted to create a method that takes any arguments you can use the standard args string for the takes argument.

How do we deal with instance variables in SDynObject? This is best illustrated with an example.

 proc Bat obj {
  $obj v foo
  ...
 }

In the example above we have just set the variable v and it will be held within our object.

How do we reference the given variable:

 proc Bat obj {
  $obj v foo
  puts [$obj v]
  return $obj
 }

In the example above puts [$obj v] will print foo.

How do we access the object that refers to the method we are in?

 proc Bat obj {
  sd.new.method hit.ball for $obj takes ball {
   $self v $ball
  }
  return $obj
 }

In the example above $self is like the $obj. It's the same token value. $self connects all methods to a single object. You can use $self to call methods within an object too, as in $self->some.method.

Now how do we create a method within a method?

 proc Bat obj {
  sd.new.method create.anew for $obj takes name {
   sd.new.method $name for $self takes args {
    puts "$self $args"
   }
  }
  return $obj
 }

How is multiple-inheritance done in SDynObject? We use several procedures and an object is passed to them so that it inherits methods and variables. For example:

 proc Object obj {
  $obj x 1
  $obj y 1
  $obj z 1
  $obj name Object

  sd.new.method move for $obj takes {x y z} {
   $self x $x
   $self y $y
   $self z $z
  }
  return $obj
 }

 proc Ball obj {
  $obj name Ball ;#inherit methods and variables from Object

  sd.new.method roll for $obj takes direction {
   if {"n" == $direction} {
    #roll ball north
   } elseif {"e" == $direction} {
    #roll ball east
   }
   ...
  }
  return $obj
 }

 set b [Ball [Object [sd.new.object]]]

 $b->move 5 4 3
 $b->roll n

Tcl and Tk use a -textvariable option that is very handy, but how do we do such a thing with SDynObject instance variables?

 proc Class obj {
  $obj v foo
  return $obj
 }

 set c [Class [sd.new.object]]

 pack [entry .e -textvariable [sd.dereference $c v]]
 #.e should now display foo

How do we destroy an object's variables and methods?

 sd.destroy.object $obj

Note: I may eventually make it be done via $obj->destroy.

For further information I suggest that you study SDynObject.tcl It's less than 50 lines of code and in my opinion quite easy to understand.

The code for SDynObject.tcl:

 #SDynObject 29
 #By George Peter Staplin
 #Get it, use it, share it, improve it, but don't blame me.

 package provide SDynObject 1.0
 set ::sd_instance_cmd {
  if {1 == [llength $args]} {
   return [set objAr([lindex $args 0])]
  } elseif {2 == [llength $args]} {
   array set objAr $args
  } else {
   return -code error "$obj key ?value?"
  }
 }

 proc sd.dereference {objId v} {
  return "::sd_instance_[set objId]($v)"
 }

 proc sd.destroy.object obj { 
  if {[info exists ::sd_methods_$obj]} {
   foreach m [set ::sd_methods_$obj] {
    catch {rename $m {}}     
   }
  }
  array unset ::sd_instance_$obj
  catch {rename $obj {}}
 }

 proc sd.get.unique.command.name {} {
  while 1 {
   if {"" == [info commands [set n cmd[clock clicks]]]} {
    return $n
   }
  }
 }

 proc sd.new.method {m _for_ obj _takes_ argList body} {
  lappend ::sd_methods_$obj $obj->$m
  proc $obj->$m $argList "set self $obj\n$body"
 }

 proc sd.new.object {} {
  proc [set n [sd.get.unique.command.name]] \
   args "upvar #0 sd_instance_$n objAr; $::sd_instance_cmd"
  sd.new.method destroy for $n takes {} [list sd.destroy.object $n]
  return $n
 }