Version 26 of ::oo:: too

Updated 2018-01-16 18:31:30 by jsuntheimer72

Prolegomenon

TclOO. Okay, got it.

I'm not much for extraneous syntax, but if you have to have it, ::oo:: is not a bad way to go. Looks cool. Pew pew pew, it's a spaceship. Or a spider. Maybe it's a moose. Maybe it's looking deeply into the eyes of a lover. ::oo:: is pretty cool, as far as syntax goes.

Well, it's been a long stretch in the JavaScript mines, better brush up on my canon.

TO THE WIKI! ALOHA!!

 Commands
 ::oo::class          new in 8.6
 ::oo::copy           new in 8.6
 ::oo::define         new in 8.6
 ::oo::objdefine
 ::oo::object
 info
 info class           provides introspection of classes (many subcommands)
 info object          provides introspection of objects (many subcommands)

 Method Commands      The following commands are only available within the body of a method
 my                   new in 8.6
 next                 new in 8.6 
 self                 new in 8.6

Now, I'm not one of them big city software architects, but I can't help but notice there are some top level tcl commands, and all I know about them right now is that they are brand-spanking new, and they are only available within the body of a method. This feels, subtly, ever so slightly, on the fringes of my spider-sense, like name space pollution. Like, if ever there was a reason to use namespaces, wouldn't it be to prevent commands that can only be used in a specific context from becoming top level commands? I'm just thinking out loud here. We'll see later if perhaps some radical language modification or maybe a complex, streaming build system might come to our rescue on that.

Okay, folks, shows over. That's TclOO, you've seen it, time to get codi..

Wait- I think I've seen that spaceship-spider-moose lover before. Was her name Valerie? No, that's not it...

 noop Sherlock/Mr. Robot-style eidetic memory sequence ensues, consisting mostly of tcl code, sandworms, and Stevie Nicks

Wait, I know! It was in the Tcllib 1.18 documentation! Yeah, it was ::oo::util, and of course, its twin, the other ::oo::util! I knew I saw it before. Wait, not just there, but.. somewhere..

 noop Fragments from Madonna's 1984 video "Borderline" flash in rapid succession

No, it wasn't in the Tcllib 1.18 documentation, it was in the "README of Changes" of Tcllib 1.18! Of course it was, it was there the whole time, and we learned the true TclOO was the friendships we made along the way.

 oodialect       oo::dialect         0.3

 oometa          oo::meta            0.4.1
                 oo::option          0.3

No, I'm wrong. Nothing here but a third of an infinite language, less than half of a meta infinity, and a ukulele option.

Hold on just a gosh darn minute! That's not even a tiny bit of a meta infinity, let alone almost half of one. It's that silly tcl namespacing, isn't it?

::::::::::::::::::::::::::::::::::info tclversion
::info tclversion
info tclversion

Never judge a namespace by the number of preceding colons. That's what pappy used ta always say.

So herm, maybe that's all of them? Maybe it would do for now. So now what are we looking at again?

   Commands
 ::oo::class            new in 8.6
 ::oo::copy             new in 8.6
 ::oo::define           new in 8.6
 ::oo::objdefine        new in France
 ::oo::object           big in Japan
 ::oo::util             namespaces solve problems
 ::oo::util             twice as nice as the last ::oo::util
 ::oo::dialect          new in tcllib 1.18 release notes
 ::oo::meta             new in tcllib 1.18 release notes
 ::oo::option           new in tcllib 1.18 release notes
 ::info
 ::info class           provides introspection of classes (many subcommands)
 ::info object          provides introspection of objects (many subcommands)

 Method Commands        The following commands are only available within the body of a method
 ::my                   new in 8.6
 ::next                 new in 8.6 
 ::self                 to thine be true

Stay classy, Tcl

Here's something from the wiki that you don't see every day

 package require TclOO
 namespace import oo::*

hmmmmm.. I say let's give it the old college try

namespace import oo::*

So now class, object, copy, define, objdefine, info, my, next, & self boldly venture together into the global namespace. Now I can immediately see the upside of the ::oo:: namespace. "copy" and "define" don't especially scream to one's intuition, "I'm here to orient objectation!"

Lets try a OO finger exercise:

namespace import oo::*

class create AClass
set instance1 [AClass new]
AClass create instance2
#instance1 destroy           error!
instance2 destroy
AClass destroy
class destroy

Okay, that's a little weird. Not sure why instance2 can be destroyed, and instance1 isn't as happy to do so. TO THE DOCS!

https://www.tcl.tk/man/tcl/TclCmd/class.htm

  cls new ?arg ...?
  Note that this method is not exported by the oo::class object itself, so classes should not be created using this method.

Ah! So, don't do that. It's available, but clearly it has issues, and we have been warned. [class create] & [cls create] it is. Learning is power!


comment 2018-01-16: the reason set instance1 [AClass new] ; instance1 destroy doesn't work is that it is trying to destroy an object called instance1. instance1 is the name of a variable which contains an object name. Try set instance1 [AClass new] ; $instance1 destroy instead.

Thank you, stranger! You are indeed correct. Mea culpa.

namespace import oo::*

class create AClass
set instance1 [AClass new]
AClass create instance2
$instance1 destroy         ;# look ma, no errors!
instance2 destroy
AClass destroy
class destroy

Also, I haven't figured out how to recover from [class destroy]. If you are following along at home, you probably want to fire up a new interpreter.

An 00 classic:

namespace import oo::*

class create Counter {
   constructor {{num 0}} {
     variable count
     set count $num
   }
   method increment {{num 1}} {
     variable count
     incr count $num
   }
   method decrement {{num 1}} {
     variable count
     incr count -$num
   }
   method currentcount {} {
     variable count
     return $count
   }
   destructor {}
}

Counter create counter

puts [counter currentcount]
counter increment
counter increment 5
puts [counter currentcount]
counter decrement
counter decrement 3
puts [counter currentcount]

Having originally discovered Tcl when downloading Ruby to play with some Pragmatic Programmers stuff back when dinosaurs yet roamed the earth, the word DRY springs to mind. I wonder if we can refactor this a bit, and get rid of some of those annoying [variable] commands.

We can! By shifting the [variable] command out of the constructor, and into the class definition, we can simplify our code.

namespace import oo::*

class create Counter {
  variable count
  constructor {{num 0}} {
    set count $num
  }
  method increment {{num 1}} {
    incr count $num
  }
  method decrement {{num 1}} {
    incr count -$num
  }
  method currentcount {} {
    return $count
  }
  destructor {}
}

Defining Definition

Sweet! But wait? methods? constructors? variables? I don't remember reading about any of that stuff in the [::oo::class] man page. I wonder if it just uses magic and pulls these out of the anonymous global array ::() somehow. Hmm, now that you mention it, I seem to recall..

  noop Montage of Benedict Cumberbatch as Dr. Strange, interspersed with the male background dancers from Madonna's 1990 video "Vogue."    

Okay, I don't even want to know what that was about.

  The constructor of the oo::class class takes an optional argument which, if present, is sent to the oo::define command 
  (along with the name of the newly-created class) to allow the class to be conveniently configured at creation time.

Ah! The top class of the hierarchy is mostly just a hollow shell, s̶o̶m̶e̶w̶h̶a̶t̶ ̶b̶r̶o̶k̶e̶n̶ ̶i̶n̶ ̶i̶t̶s̶e̶l̶f̶, benefiting from the efforts of others. Go fig.

CONFIGURING CLASSES

'oo::define class defScript
'oo::define
class subcommand arg ?arg ...?

constructor argList bodyScript
deletemethod name ?name ...
destructor bodyScript
export name ?name ...?
filter ?-slotOperation? ?methodName ...?
forward name cmdName ?arg ...?
method name argList bodyScript
mixin ?-slotOperation? ?className ...?
renamemethod fromName toName
self subcommand arg ...
self script
superclass ?-slotOperation? ?className ...?
unexport name ?name ...?
variable ?-slotOperation? ?name ...?

Rise, [define]! Unshackle yourself from the imperialist ruling [class]. YOU CONTROL THE MEANS OF PRODUCTION! Viva la revolución!

namespace import oo::*

class create Counter

define Counter variable count
define Counter constructor {{num 0}} { set count $num }
define Counter method increment {{num 1}} { incr count $num }
define Counter method decrement {{num 1}} { incr count -$num }
define Counter method currentcount {} { return $count }

Counter create counter

puts [counter currentcount]
counter increment
counter increment 5
puts [counter currentcount]
counter decrement
counter decrement 3
puts [counter currentcount]

So that's pretty cool. That's seems about as dynamic as it gets. [define] reminds me of that TAHITI machine that rebuilt Agent Coulson's brain. [define] is a magical command.

Now, honestly, I was about to move on to the OO classic, "A home is a house with a family and a pet," but I'm feeling inspired.

Superclasses for Superagents

namespace import oo::*

class create Organization {
  variable taxID members
  constructor {taxid} {
    set taxID $taxid
  }
  method getTaxID {} {
    return $taxID
  }
}

class create SecretSpyOrganization {
  superclass Organization
  variable alignment
  constructor {taxid align} {
    set alignment $align
    next $taxid
  }
  method getAlignment {} {
    return $alignment
  }
}

SecretSpyOrganization create SHIELD 007 good
SecretSpyOrganization create HYDRA 666 evil

puts [SHIELD getTaxID]
puts [HYDRA getAlignment]