bionic (3) snitfaq.3tcl.gz

Provided by: tcllib_1.19-dfsg-2_all bug

NAME

       snitfaq - Snit Frequently Asked Questions

DESCRIPTION

OVERVIEW

   WHAT IS THIS DOCUMENT?
       This  is  an atypical FAQ list, in that few of the questions are frequently asked.  Rather, these are the
       questions I think a newcomer to Snit should be asking.  This file is not a complete  reference  to  Snit,
       however; that information is in the snit man page.

   WHAT IS SNIT?
       Snit is a framework for defining abstract data types and megawidgets in pure Tcl.  The name "Snit" stands
       for "Snit's Not Incr Tcl", signifying that Snit takes a different approach to defining objects than  does
       Incr Tcl, the best known object framework for Tcl.  Had I realized that Snit would become at all popular,
       I'd probably have chosen something else.

       The primary purpose of Snit is to be object glue--to  help  you  compose  diverse  objects  from  diverse
       sources  into  types  and megawidgets with clean, convenient interfaces so that you can more easily build
       your application.

       Snit isn't about theoretical purity or minimalist design; it's about being able  to  do  powerful  things
       easily  and consistently without having to think about them--so that you can concentrate on building your
       application.

       Snit  isn't  about  implementing  thousands   of   nearly   identical   carefully-specified   lightweight
       thingamajigs--not  as individual Snit objects.  Traditional Tcl methods will be much faster, and not much
       more complicated.  But Snit is about implementing a clean interface to manage a collection  of  thousands
       of nearly identical carefully-specified lightweight thingamajigs (e.g., think of the text widget and text
       tags, or the canvas widget and canvas objects).  Snit lets  you  hide  the  details  of  just  how  those
       thingamajigs are stored--so that you can ignore it, and concentrate on building your application.

       Snit  isn't  a  way  of  life,  a  silver  bullet,  or the Fountain of Youth. It's just a way of managing
       complexity--and of managing some of the complexity of managing complexity--so that you can concentrate on
       building your application.

   WHAT VERSION OF TCL DOES SNIT REQUIRE?
       Snit  1.3  requires  Tcl  8.3  or  later;  Snit 2.2 requires Tcl 8.5 or later.  See SNIT VERSIONS for the
       differences between Snit 1.3 and Snit 2.2.

   WHERE CAN I DOWNLOAD SNIT?
       Snit is part of Tcllib, the standard Tcl library, so you might already have it.  It's also  available  at
       the Snit Home Page, http://www.wjduquette.com/snit.

   WHAT ARE SNIT'S GOALS?
       •      A   Snit   object   should   be   at   least   as  efficient  as  a  hand-coded  Tcl  object  (see
              http://www.wjduquette.com/tcl/objects.html).

       •      The fact that Snit was used in an object's implementation should be transparent  (and  irrelevant)
              to clients of that object.

       •      Snit should be able to encapsulate objects from other sources, particularly Tk widgets.

       •      Snit  megawidgets  should  be  (to  the  extent  possible)  indistinguishable in interface from Tk
              widgets.

       •      Snit should be Tclish--that is, rather than trying to emulate C++, Smalltalk, or anything else, it
              should try to emulate Tcl itself.

       •      It should have a simple, easy-to-use, easy-to-remember syntax.

   HOW IS SNIT DIFFERENT FROM OTHER OO FRAMEWORKS?
       Snit is unique among Tcl object systems in that it is based not on inheritance but on delegation.  Object
       systems based on inheritance only allow you to inherit from classes defined using the  same  system,  and
       that's  a  shame.   In  Tcl,  an object is anything that acts like an object; it shouldn't matter how the
       object was implemented.  I designed Snit to help me build applications out  of  the  materials  at  hand;
       thus,  Snit  is  designed  to  be  able to incorporate and build on any object, whether it's a hand-coded
       object, a Tk widget, an Incr Tcl object, a BWidget or almost anything else.

       Note that you can achieve the effect of inheritance using COMPONENTS and DELEGATION--and you can  inherit
       from anything that looks like a Tcl object.

   WHAT CAN I DO WITH SNIT?
       Using Snit, a programmer can:

       •      Create abstract data types and Tk megawidgets.

       •      Define instance variables, type variables, and Tk-style options.

       •      Define constructors, destructors, instance methods, type methods, procs.

       •      Assemble  a  type  out  of  component types.  Instance methods and options can be delegated to the
              component types automatically.

SNIT VERSIONS

   WHICH VERSION OF SNIT SHOULD I USE?
       The current Snit distribution includes two versions, Snit 1.3 and Snit 2.2.  The  reason  that  both  are
       included  is  that  Snit  2.2  takes advantage of a number of new features of Tcl 8.5 to improve run-time
       efficiency; as a side-effect, the ugliness of Snit's error messages and stack  traces  has  been  reduced
       considerably.  The cost of using Snit 2.2, of course, is that you must target Tcl 8.5.

       Snit 1.3, on the other hand, lacks Snit 2.2's optimizations, but requires only Tcl 8.3 and later.

       In  short,  if you're targetting Tcl 8.3 or 8.4 you should use Snit 1.3.  If you can afford to target Tcl
       8.5, you should definitely use Snit 2.2.   If  you  will  be  targetting  both,  you  can  use  Snit  1.3
       exclusively,  or (if your code is unaffected by the minor incompatibilities between the two versions) you
       can use Snit 1.3 for Tcl 8.4 and Snit 2.2 for Tcl 8.5.

   HOW DO I SELECT THE VERSION OF SNIT I WANT TO USE?
       To always use Snit 1.3 (or a later version of Snit 1.x), invoke Snit as follows:

              package require snit 1.3

       To always use Snit 2.2 (or a later version of Snit 2.x), say this instead:

              package require snit 2.2

       Note that if you request Snit 2.2 explicitly, your application will halt with Tcl 8.4, since Snit 2.2  is
       unavailable for Tcl 8.4.

       If  you wish your application to always use the latest available version of Snit, don't specify a version
       number:

              package require snit

       Tcl will find and load the latest version that's available relative to the version of Tcl being used.  In
       this case, be careful to avoid using any incompatible features.

   HOW ARE SNIT 1.3 AND SNIT 2.2 INCOMPATIBLE?
       To  the  extent  possible,  Snit 2.2 is intended to be a drop-in replacement for Snit 1.3. Unfortunately,
       some incompatibilities were inevitable because Snit 2.2 uses Tcl 8.5's new namespace  ensemble  mechanism
       to  implement subcommand dispatch.  This approach is much faster than the mechanism used in Snit 1.3, and
       also  results  in  much  better  error  messages;  however,  it  also  places  new  constraints  on   the
       implementation.

       There are four specific incompatibilities between Snit 1.3 and Snit 2.2.

       •      Snit  1.3  supports  implicit  naming of objects.  Suppose you define a new snit::type called dog.
              You can create instances of dog in three ways:

              dog spot               ;# Explicit naming
              set obj1 [dog %AUTO%]  ;# Automatic naming
              set obj2 [dog]         ;# Implicit naming

              In Snit 2.2, type commands are defined using  the  namespace  ensemble  mechanism;  and  namespace
              ensemble  doesn't  allow  an  ensemble command to be called without a subcommand.  In short, using
              namespace ensemble there's no way to support implicit naming.

              All is not lost, however.  If the type has no type methods, then the  type  command  is  a  simple
              command  rather  than  an  ensemble,  and  namespace ensemble is not used.  In this case, implicit
              naming is still possible.

              In short, you can have implicit naming if you're willing to do without type methods (including the
              standard type methods, like $type info).  To do so, use the -hastypemethods pragma:

              pragma -hastypemethods 0

       •      Hierarchical methods and type methods are implemented differently in Snit 2.2.

              A  hierarchical  method  is  an  instance  method  which  has  subcommands;  these subcommands are
              themselves methods.  The Tk text  widget's  tag  command  and  its  subcommands  are  examples  of
              hierarchical  methods.   You  can  implement such subcommands in Snit simply by including multiple
              words in the method names:

              method {tag configure} {tag args} { ... }

              method {tag cget} {tag option} {...}

              Here we've implicitly defined a tag method which has two subcommands, configure and cget.

              In Snit 1.3, hierarchical methods could be called in two ways:

              $obj tag cget -myoption      ;# The good way
              $obj {tag cget} -myoption    ;# The weird way

              In the second call, we see that a hierarchical method or type method  is  simply  one  whose  name
              contains multiple words.

              In  Snit  2.2  this is no longer the case, and the "weird" way of calling hierarchical methods and
              type methods no longer works.

       •      The third incompatibility derives from the second.  In Snit 1.3, hierarchical  methods  were  also
              simply  methods  whose  name contains multiple words.  As a result, $obj info methods returned the
              full names of all hierarchical methods.  In the example above, the  list  returned  by  $obj  info
              methods  would  include  tag  configure  and  tag  cget  but  not  tag,  since tag is defined only
              implicitly.

              In Snit 2.2, hierarchical methods and type methods are no longer simply ones whose  name  contains
              multiple words; in the above example, the list returned by $obj info methods would include tag but
              not tag configure or tag cget.

       •      The fourth incompatibility is due to a new feature.  Snit 2.2 uses the new namespace path  command
              so  that  a  type's  code  can  call  any  command  defined in the type's parent namespace without
              qualification or importation.  For example, suppose you have  a  package  called  mypackage  which
              defines a number of commands including a type, ::mypackage::mytype.  Thanks to namespace path, the
              type's code can call any of the other commands defined in ::mypackage::.

              This is extremely convenient.  However,  it  also  means  that  commands  defined  in  the  parent
              namespace,  ::mypackage::  can block the type's access to identically named commands in the global
              namespace.  This can lead to bugs.  For example, Tcllib includes a type  called  ::tie::std::file.
              This  type's  code  calls the standard file command.  When run with Snit 2.2, the code broke-- the
              type's command, ::tie::std::file, is itself a command in  the  type's  parent  namespace,  and  so
              instead of calling the standard file command, the type found itself calling itself.

   ARE THERE OTHER DIFFERENCES BETWEEN SNIT 1.X AND SNIT 2.2?
       Yes.

       •      Method dispatch is considerably faster.

       •      Many error messages and stack traces are cleaner.

       •      The  -simpledispatch  pragma  is  obsolete,  and  ignored if present. In Snit 1.x, -simpledispatch
              substitutes a faster mechanism for method dispatch, at the cost of losing certain features.   Snit
              2.2 method dispatch is faster still in all cases, so -simpledispatch is no longer needed.

       •      In  Snit 2.2, a type's code (methods, type methods, etc.) can call commands from the type's parent
              namespace without qualifying or importing them, i.e.,  type  ::parentns::mytype's  code  can  call
              ::parentns::someproc as just someproc.

              This  is  extremely useful when a type is defined as part of a larger package, and shares a parent
              namespace with the rest of the package; it means that the type can call other commands defined  by
              the package without any extra work.

              This  feature  depends  on  the  new  Tcl  8.5 namespace path command, which is why it hasn't been
              implemented for V1.x.  V1.x code can achieve something similar by placing

              namespace import [namespace parent]::*

              in a type constructor.  This is less useful, however, as it picks up  only  those  commands  which
              have already been exported by the parent namespace at the time the type is defined.

OBJECTS

   WHAT IS AN OBJECT?
       A  full description of object-oriented programming is beyond the scope of this FAQ, obviously.  In simple
       terms, an object is an instance of an abstract data type--a coherent bundle of code and data.  There  are
       many ways to represent objects in Tcl/Tk; the best known examples are the Tk widgets.

       A  Tk  widget  is an object; it is represented by a Tcl command.  The object's methods are subcommands of
       the Tcl command.  The object's properties are options accessed using  the  configure  and  cget  methods.
       Snit uses the same conventions as Tk widgets do.

   WHAT IS AN ABSTRACT DATA TYPE?
       In  computer  science  terms,  an  abstract  data  type  is  a complex data structure along with a set of
       operations--a stack, a queue, a binary tree, etc--that is to say, in modern terms, an object.  In systems
       that  include  some form of inheritance the word class is usually used instead of abstract data type, but
       as Snit  doesn't  implement  inheritance  as  it's  ordinarily  understood  the  older  term  seems  more
       appropriate.    Sometimes   this  is  called  object-based  programming  as  opposed  to  object-oriented
       programming.  Note that you can easily create the effect of inheritance using COMPONENTS and DELEGATION.

       In Snit, as in Tk, a type is a command that creates instances -- objects -- which  belong  to  the  type.
       Most  types  define  some number of options which can be set at creation time, and usually can be changed
       later.

       Further, an instance is also a Tcl command--a command that gives  access  to  the  operations  which  are
       defined  for  that  abstract data type.  Conventionally, the operations are defined as subcommands of the
       instance command.  For example, to insert text into a Tk text widget, you use the  text  widget's  insert
       subcommand:

                  # Create a text widget and insert some text in it.
                  text .mytext -width 80 -height 24
                  .mytext insert end "Howdy!"

       In this example, text is the type command and .mytext is the instance command.

       In Snit, object subcommands are generally called INSTANCE METHODS.

   WHAT KINDS OF ABSTRACT DATA TYPES DOES SNIT PROVIDE?
       Snit allows you to define three kinds of abstract data type:

       •      snit::typesnit::widgetsnit::widgetadaptor

   WHAT IS A SNIT::TYPE?
       A  snit::type  is  a non-GUI abstract data type, e.g., a stack or a queue.  snit::types are defined using
       the snit::type command.  For example, if you were designing a kennel management system for a dog breeder,
       you'd need a dog type.

              % snit::type dog {
                  # ...
              }
              ::dog
              %

       This definition defines a new command (::dog, in this case) that can be used to define dog objects.

       An  instance of a snit::type can have INSTANCE METHODS, INSTANCE VARIABLES, OPTIONS, and COMPONENTS.  The
       type itself can have TYPE METHODS, TYPE VARIABLES, TYPE COMPONENTS, and PROCS.

   WHAT IS A SNIT::WIDGET?, THE SHORT STORY
       A snit::widget is a Tk megawidget built using Snit; it is very similar to a snit::type.  See WIDGETS.

   WHAT IS A SNIT::WIDGETADAPTOR?, THE SHORT STORY
       A snit::widgetadaptor uses Snit to wrap an existing  widget  type  (e.g.,  a  Tk  label),  modifying  its
       interface to a lesser or greater extent.  It is very similar to a snit::widget.  See WIDGET ADAPTORS.

   HOW DO I CREATE AN INSTANCE OF A SNIT::TYPE?
       You  create  an  instance of a snit::type by passing the new instance's name to the type's create method.
       In the following example, we create a dog object called spot.

              % snit::type dog {
                  # ....
              }
              ::dog
              % dog create spot
              ::spot
              %

       In general, the create method name can be omitted so long as the instance name doesn't conflict with  any
       defined  TYPE  METHODS.  (See  TYPE  COMPONENTS for the special case in which this doesn't work.)  So the
       following example is identical to the previous example:

              % snit::type dog {
                  # ....
              }
              ::dog
              % dog spot
              ::spot
              %

       This document generally uses the shorter form.

       If the dog type defines OPTIONS, these can usually be given defaults at creation time:

              % snit::type dog {
                  option -breed mongrel
                  option -color brown

                  method bark {} { return "$self barks." }
              }
              ::dog
              % dog create spot -breed dalmation -color spotted
              ::spot
              % spot cget -breed
              dalmation
              % spot cget -color
              spotted
              %

       Once created, the instance name now names a new Tcl command that is used to manipulate the  object.   For
       example, the following code makes the dog bark:

              % spot bark
              ::spot barks.
              %

   HOW DO I REFER TO AN OBJECT INDIRECTLY?
       Some programmers prefer to save the object name in a variable, and reference it that way.  For example,

              % snit::type dog { ... }
              ::dog
              % set d [dog spot -breed dalmation -color spotted]
              ::spot
              % $d cget -breed
              dalmation
              % $d bark
              ::spot barks.
              %

       If you prefer this style, you might prefer to have Snit generate the instance's name automatically.

   HOW CAN I GENERATE THE OBJECT NAME AUTOMATICALLY?
       If you'd like Snit to generate an object name for you, use the %AUTO% keyword as the requested name:

              % snit::type dog { ... }
              ::dog
              % set d [dog %AUTO%]
              ::dog2
              % $d bark
              ::dog2 barks.
              %

       The %AUTO% keyword can be embedded in a longer string:

              % set d [dog obj_%AUTO%]
              ::obj_dog4
              % $d bark
              ::obj_dog4 barks.
              %

   CAN TYPES BE RENAMED?
       Tcl's  rename  command  renames  other  commands.   It's  a common technique in Tcl to modify an existing
       command by renaming it and defining a new command with the original name; the new command  usually  calls
       the renamed command.

       snit::type  commands,  however,  should never be renamed; to do so breaks the connection between the type
       and its objects.

   CAN OBJECTS BE RENAMED?
       Tcl's rename command renames other commands.  It's a common  technique  in  Tcl  to  modify  an  existing
       command  by  renaming it and defining a new command with the original name; the new command usually calls
       the renamed command.

       All Snit objects (including widgets and widgetadaptors) can be renamed, though this flexibility has  some
       consequences:

       •      In  an  instance method, the implicit argument self will always contain the object's current name,
              so instance methods can always call other instance methods using $self.

       •      If the object is renamed, however, then $self's value will change.  Therefore, don't use $self for
              anything  that  will break if $self changes. For example, don't pass a callback command to another
              object like this:

                  .btn configure -command [list $self ButtonPress]

              You'll get an error if .btn calls your command after your object is renamed.

       •      Instead, your object should define its callback command like this:

                  .btn configure -command [mymethod ButtonPress]

              The mymethod command returns code that will call the desired method  safely;  the  caller  of  the
              callback can add additional arguments to the end of the command as usual.

       •      Every  object  has  a private namespace; the name of this namespace is available in method bodies,
              etc., as the value of the implicit argument selfns.  This value is constant for the  life  of  the
              object.  Use $selfns instead of $self if you need a unique token to identify the object.

       •      When  a  snit::widget's instance command is renamed, its Tk window name remains the same -- and is
              still extremely important. Consequently, the Tk window name is available in method bodies  as  the
              value  of  the  implicit  argument  win.  This value is constant for the life of the object.  When
              creating child windows, it's best to use $win.child rather than $self.child as  the  name  of  the
              child window.

   HOW DO I DESTROY A SNIT OBJECT?
       Any  Snit  object  of  any  type can be destroyed by renaming it to the empty string using the Tcl rename
       command.

       Snit megawidgets (i.e., instances of snit::widget and snit::widgetadaptor)  can  be  destroyed  like  any
       other  widget:  by  using  the  Tk destroy command on the widget or on one of its ancestors in the window
       hierarchy.

       Every instance of a snit::type has a destroy method:

              % snit::type dog { ... }
              ::dog
              % dog spot
              ::spot
              % spot bark
              ::spot barks.
              % spot destroy
              % spot barks
              invalid command name "spot"
              %

       Finally, every Snit type has a type method called destroy; calling it destroys the type and  all  of  its
       instances:

              % snit::type dog { ... }
              ::dog
              % dog spot
              ::spot
              % spot bark
              ::spot barks.
              % dog destroy
              % spot bark
              invalid command name "spot"
              % dog fido
              invalid command name "dog"
              %

INSTANCE METHODS

   WHAT IS AN INSTANCE METHOD?
       An  instance  method  is  a procedure associated with a specific object and called as a subcommand of the
       object's command.  It is given free access to all of the object's type variables, instance variables, and
       so forth.

   HOW DO I DEFINE AN INSTANCE METHOD?
       Instance  methods  are defined in the type definition using the method statement.  Consider the following
       code that might be used to add dogs to a computer simulation:

              % snit::type dog {
                  method bark {} {
                      return "$self barks."
                  }

                  method chase {thing} {
                      return "$self chases $thing."
                  }
              }
              ::dog
              %

       A dog can bark, and it can chase things.

       The method statement looks just like  a  normal  Tcl  proc,  except  that  it  appears  in  a  snit::type
       definition.   Notice  that  every  instance  method  gets an implicit argument called self; this argument
       contains the object's name.  (There's more on implicit method arguments below.)

   HOW DOES A CLIENT CALL AN INSTANCE METHOD?
       The method name becomes a subcommand of the object.  For example, let's put a simulated dog  through  its
       paces:

              % dog spot
              ::spot
              % spot bark
              ::spot barks.
              % spot chase cat
              ::spot chases cat.
              %

   HOW DOES AN INSTANCE METHOD CALL ANOTHER INSTANCE METHOD?
       If  method A needs to call method B on the same object, it does so just as a client does: it calls method
       B as a subcommand of the object itself, using the object name stored in the implicit argument self.

       Suppose, for example, that our dogs never chase anything without barking at them:

              % snit::type dog {
                  method bark {} {
                      return "$self barks."
                  }

                  method chase {thing} {
                      return "$self chases $thing.  [$self bark]"
                  }
              }
              ::dog
              % dog spot
              ::spot
              % spot bark
              ::spot barks.
              % spot chase cat
              ::spot chases cat.  ::spot barks.
              %

   ARE THERE ANY LIMITATIONS ON INSTANCE METHOD NAMES?
       Not really, so long as you avoid the standard instance  method  names:  configure,  configurelist,  cget,
       destroy, and info.  Also, method names consisting of multiple words define hierarchical methods.

   WHAT IS A HIERARCHICAL METHOD?
       An  object's  methods  are  subcommands  of the object's instance command.  Hierarchical methods allow an
       object's methods to have subcommands of their own; and these can in turn have  subcommands,  and  so  on.
       This  allows  the programmer to define a tree-shaped command structure, such as is used by many of the Tk
       widgets--the subcommands of the Tk text widget's tag method are hierarchical methods.

   HOW DO I DEFINE A HIERARCHICAL METHOD?
       Define methods whose names consist of multiple words.  These words define the hierarchy implicitly.   For
       example, the following code defines a tag method with subcommands cget and configure:

              snit::widget mytext {
                  method {tag configure} {tag args} { ... }

                  method {tag cget} {tag option} {...}
              }

       Note  that  there  is  no explicit definition for the tag method; it is implicit in the definition of tag
       configure and tag cget.  If you tried to define tag explicitly in this example, you'd get an error.

   HOW DO I CALL HIERARCHICAL METHODS?
       As subcommands of subcommands.

              % mytext .text
              .text
              % .text tag configure redtext -foreground red -background black
              % .text tag cget redtext -foreground
              red
              %

   HOW DO I MAKE AN INSTANCE METHOD PRIVATE?
       It's often useful to define private methods, that is, instance methods intended  to  be  called  only  by
       other methods of the same object.

       Snit  doesn't  implement  any  access  control  on  instance methods, so all methods are de facto public.
       Conventionally, though, the names of public methods begin with a lower-case  letter,  and  the  names  of
       private methods begin with an upper-case letter.

       For  example, suppose our simulated dogs only bark in response to other stimuli; they never bark just for
       fun.  So the bark method becomes Bark to indicate that it is private:

              % snit::type dog {
                  # Private by convention: begins with uppercase letter.
                  method Bark {} {
                      return "$self barks."
                  }

                  method chase {thing} {
                      return "$self chases $thing. [$self Bark]"
                  }
              }
              ::dog
              % dog fido
              ::fido
              % fido chase cat
              ::fido chases cat. ::fido barks.
              %

   ARE THERE ANY LIMITATIONS ON INSTANCE METHOD ARGUMENTS?
       Method argument lists are defined just like normal Tcl proc  argument  lists;  in  particular,  they  can
       include arguments with default values and the args argument.

       However,  every  method  also  has  a  number of implicit arguments provided by Snit in addition to those
       explicitly defined.  The names of these implicit arguments may not used to name explicit arguments.

   WHAT IMPLICIT ARGUMENTS ARE PASSED TO EACH INSTANCE METHOD?
       The arguments implicitly passed to every method are type, selfns, win, and self.

   WHAT IS $TYPE?
       The implicit argument type contains the fully qualified name of the object's type:

              % snit::type thing {
                  method mytype {} {
                      return $type
                  }
              }
              ::thing
              % thing something
              ::something
              % something mytype
              ::thing
              %

   WHAT IS $SELF?
       The implicit argument self contains the object's fully qualified name.

       If the object's command is renamed, then $self will change to match in subsequent calls.  Thus, your code
       should not assume that $self is constant unless you know for sure that the object will never be renamed.

              % snit::type thing {
                  method myself {} {
                      return $self
                  }
              }
              ::thing
              % thing mutt
              ::mutt
              % mutt myself
              ::mutt
              % rename mutt jeff
              % jeff myself
              ::jeff
              %

   WHAT IS $SELFNS?
       Each  Snit  object  has  a  private  namespace in which to store its INSTANCE VARIABLES and OPTIONS.  The
       implicit argument selfns contains the name of this namespace; its value never changes,  and  is  constant
       for the life of the object, even if the object's name changes:

              % snit::type thing {
                  method myNameSpace {} {
                      return $selfns
                  }
              }
              ::thing
              % thing jeff
              ::jeff
              % jeff myNameSpace
              ::thing::Snit_inst3
              % rename jeff mutt
              % mutt myNameSpace
              ::thing::Snit_inst3
              %

       The  above  example reveals how Snit names an instance's private namespace; however, you should not write
       code that depends on the specific naming convention, as it might change in future releases.

   WHAT IS $WIN?
       The implicit argument win is defined for all Snit methods, though it really makes sense only for those of
       WIDGETS  and  WIDGET ADAPTORS.  $win is simply the original name of the object, whether it's been renamed
       or not.  For widgets and widgetadaptors, it is also therefore the name of a Tk window.

       When a snit::widgetadaptor is used to modify the interface of a widget or megawidget, it must rename  the
       widget's original command and replace it with its own.

       Thus,   using   win   whenever   the  Tk  window  name  is  called  for  means  that  a  snit::widget  or
       snit::widgetadaptor can be adapted by a snit::widgetadaptor.  See WIDGETS for more information.

   HOW DO I PASS AN INSTANCE METHOD AS A CALLBACK?
       It depends on the context.

       Suppose in my application I have a dog object named fido, and I want fido to bark when a Tk button called
       .bark is pressed.  In this case, I create the callback command in the usual way, using list:

                  button .bark -text "Bark!" -command [list fido bark]

       In  typical  Tcl  style, we use a callback to hook two independent components together.  But suppose that
       the dog object has a graphical interface and owns the button itself?  In this case, the dog must pass one
       of its own instance methods to the button it owns.  The obvious thing to do is this:

              % snit::widget dog {
                  constructor {args} {
                      #...
                      button $win.barkbtn -text "Bark!" -command [list $self bark]
                      #...
                  }
              }
              ::dog
              %

       (Note that in this example, our dog becomes a snit::widget, because it has GUI behavior.  See WIDGETS for
       more.)  Thus, if we create a dog called .spot, it will create a  Tk  button  called  .spot.barkbtn;  when
       pressed, the button will call $self bark.

       Now, this will work--provided that .spot is never renamed to something else.  But surely renaming widgets
       is abnormal?  And so it is--unless .spot is the hull component of a snit::widgetadaptor.  If it is,  then
       it will be renamed, and .spot will become the name of the snit::widgetadaptor object.  When the button is
       pressed, the command $self bark will be handled by the snit::widgetadaptor, which might or might  not  do
       the right thing.

       There's a safer way to do it, and it looks like this:

              % snit::widget dog {
                  constructor {args} {
                      #...
                      button $win.barkbtn -text "Bark!" -command [mymethod bark]
                      #...
                  }
              }
              ::dog
              %

       The  command  mymethod  takes  any  number of arguments, and can be used like list to build up a callback
       command; the only difference is that mymethod returns a form of the command that won't change even if the
       instance's name changes.

       On  the other hand, you might prefer to allow a widgetadaptor to override a method such that your renamed
       widget will call the widgetadaptor's method instead of its own.  In this case, using  [list  $self  bark]
       will  do  what  you  want...but  this  is  a  technique which should be used only in carefully controlled
       circumstances.

   HOW DO I DELEGATE INSTANCE METHODS TO A COMPONENT?
       See DELEGATION.

INSTANCE VARIABLES

   WHAT IS AN INSTANCE VARIABLE?
       An instance variable is a private  variable  associated  with  some  particular  Snit  object.   Instance
       variables can be scalars or arrays.

   HOW IS A SCALAR INSTANCE VARIABLE DEFINED?
       Scalar  instance  variables  are  defined  in  the type definition using the variable statement.  You can
       simply name it, or you can initialize it with a value:

              snit::type mytype {
                  # Define variable "greeting" and initialize it with "Howdy!"
                  variable greeting "Howdy!"
              }

   HOW IS AN ARRAY INSTANCE VARIABLE DEFINED?
       Array instance variables are also defined in the type definition using the  variable  command.   You  can
       initialize them at the same time by specifying the -array option:

              snit::type mytype {
                  # Define array variable "greetings"
                  variable greetings -array {
                      formal "Good Evening"
                      casual "Howdy!"
                  }
              }

   WHAT HAPPENS IF I DON'T INITIALIZE AN INSTANCE VARIABLE?
       Variables  do not really exist until they are given values.  If you do not initialize a variable when you
       define it, then you must be sure to assign a value to it (in the constructor, say,  or  in  some  method)
       before you reference it.

   ARE THERE ANY LIMITATIONS ON INSTANCE VARIABLE NAMES?
       Just a few.

       First,  every  Snit  object  has  a  built-in  instance  variable  called  options, which should never be
       redefined.

       Second, all names beginning with "Snit_" are reserved for use by Snit internal code.

       Third, instance variable names containing  the  namespace  delimiter  (::)  are  likely  to  cause  great
       confusion.

   DO I NEED TO DECLARE MY INSTANCE VARIABLES IN MY METHODS?
       No.  Once you've defined an instance variable in the type definition, it can be used in any instance code
       (instance methods, the constructor, and the destructor) without declaration.  This  differs  from  normal
       Tcl practice, in which all non-local variables in a proc need to be declared.

       There  is  a  speed  penalty  to having all instance variables implicitly available in all instance code.
       Even though your code need not declare the variables explicitly, Snit must still declare them,  and  that
       takes  time.   If  you  have  ten  instance variables, a method that uses none of them must still pay the
       declaration penalty for all ten.  In most cases, the additional runtime cost is negligible.   If  extreme
       cases, you might wish to avoid it; there are two methods for doing so.

       The  first  is to define a single instance variable, an array, and store all of your instance data in the
       array.  This way, you're only paying the declaration penalty for one variable--and you probably need  the
       variable  most  of  the time anyway.  This method breaks down if your instance variables include multiple
       arrays; in Tcl 8.5, however, the dict command might come to your rescue.

       The second method is to declare your instance variables explicitly  in  your  instance  code,  while  not
       including them in the type definition:

              snit::type dog {
                  constructor {} {
                      variable mood

                      set mood happy
                  }

                  method setmood {newMood} {
                      variable mood

                      set mood $newMood
                  }

                  method getmood {} {
                      variable mood

                      return $mood
                  }
              }

       This  allows  you  to ensure that only the required variables are included in each method, at the cost of
       longer code and run-time errors when you forget to declare a variable you need.

   HOW DO I PASS AN INSTANCE VARIABLE'S NAME TO ANOTHER OBJECT?
       In Tk, it's common to pass a widget a variable name; for example, Tk label widgets have  a  -textvariable
       option  which names the variable which will contain the widget's text.  This allows the program to update
       the label's value just by assigning a new value to the variable.

       If you naively pass the instance variable name to the label widget, you'll be confused by the result;  Tk
       will  assume  that  the  name  names  a  global variable.  Instead, you need to provide a fully-qualified
       variable name.  From within an instance method or a constructor, you can  fully  qualify  the  variable's
       name using the myvar command:

              snit::widget mywidget {
                  variable labeltext ""

                  constructor {args} {
                      # ...

                      label $win.label -textvariable [myvar labeltext]

                      # ...
                  }
              }

   HOW DO I MAKE AN INSTANCE VARIABLE PUBLIC?
       Practically  speaking, you don't.  Instead, you'll implement public variables as OPTIONS.  Alternatively,
       you can write INSTANCE METHODS to set and get the variable's value.

OPTIONS

   WHAT IS AN OPTION?
       A type's options are the equivalent of what other object-oriented  languages  would  call  public  member
       variables  or properties: they are data values which can be retrieved and (usually) set by the clients of
       an object.

       Snit's implementation of options follows the Tk model fairly  exactly,  except  that  snit::type  objects
       usually  don't interact with THE TK OPTION DATABASE; snit::widget and snit::widgetadaptor objects, on the
       other hand, always do.

   HOW DO I DEFINE AN OPTION?
       Options are defined in the type definition using the option statement.  Consider the following  type,  to
       be used in an application that manages a list of dogs for a pet store:

              snit::type dog {
                  option -breed -default mongrel
                  option -color -default brown
                  option -akc   -default 0
                  option -shots -default 0
              }

       According  to  this,  a  dog has four notable properties: a breed, a color, a flag that says whether it's
       pedigreed with the American Kennel Club, and another flag that says whether it has had  its  shots.   The
       default dog, evidently, is a brown mutt.

       There  are  a number of options you can specify when defining an option; if -default is the only one, you
       can omit the word -default as follows:

              snit::type dog {
                  option -breed mongrel
                  option -color brown
                  option -akc   0
                  option -shots 0
              }

       If no -default value is specified, the option's default value will be the empty string (but  see  THE  TK
       OPTION DATABASE).

       The Snit man page refers to options like these as "locally defined" options.

   HOW CAN A CLIENT SET OPTIONS AT OBJECT CREATION?
       The  normal  convention  is  that  the  client  may pass any number of options and their values after the
       object's name at object creation.  For example, the ::dog command defined in the previous answer can  now
       be used to create individual dogs.  Any or all of the options may be set at creation time.

              % dog spot -breed beagle -color "mottled" -akc 1 -shots 1
              ::spot
              % dog fido -shots 1
              ::fido
              %

       So  ::spot  is  a  pedigreed beagle; ::fido is a typical mutt, but his owners evidently take care of him,
       because he's had his shots.

       Note: If the type defines a  constructor,  it  can  specify  a  different  object-creation  syntax.   See
       CONSTRUCTORS for more information.

   HOW CAN A CLIENT RETRIEVE AN OPTION'S VALUE?
       Retrieve option values using the cget method:

              % spot cget -color
              mottled
              % fido cget -breed
              mongrel
              %

   HOW CAN A CLIENT SET OPTIONS AFTER OBJECT CREATION?
       Any  number  of  options may be set at one time using the configure instance method.  Suppose that closer
       inspection shows that ::fido is not a brown mongrel, but rather a rare Arctic Boar Hound of a lovely  dun
       color:

              % fido configure -color dun -breed "Arctic Boar Hound"
              % fido cget -color
              dun
              % fido cget -breed
              Arctic Boar Hound

       Alternatively,  the  configurelist  method  takes a list of options and values; occasionally this is more
       convenient:

              % set features [list -color dun -breed "Arctic Boar Hound"]
              -color dun -breed {Arctic Boar Hound}
              % fido configurelist $features
              % fido cget -color
              dun
              % fido cget -breed
              Arctic Boar Hound
              %

       In Tcl 8.5, the * keyword can be used with configure in this case:

              % set features [list -color dun -breed "Arctic Boar Hound"]
              -color dun -breed {Arctic Boar Hound}
              % fido configure {*}$features
              % fido cget -color
              dun
              % fido cget -breed
              Arctic Boar Hound
              %

       The results are the same.

   HOW SHOULD AN INSTANCE METHOD ACCESS AN OPTION VALUE?
       There are two ways an instance method can set and  retrieve  an  option's  value.   One  is  to  use  the
       configure and cget methods, as shown below.

              % snit::type dog {
                  option -weight 10

                  method gainWeight {} {
                      set wt [$self cget -weight]
                      incr wt
                      $self configure -weight $wt
                  }
              }
              ::dog
              % dog fido
              ::fido
              % fido cget -weight
              10
              % fido gainWeight
              % fido cget -weight
              11
              %

       Alternatively,  Snit  provides  a  built-in  array instance variable called options.  The indices are the
       option names; the values are the option values.  The method gainWeight can thus be rewritten as follows:

                  method gainWeight {} {
                      incr options(-weight)
                  }

       As you can see, using the options variable involves considerably less typing and is the usual way  to  do
       it.   But if you use -configuremethod or -cgetmethod (described in the following answers), you might wish
       to use the configure and cget methods anyway, just so that any special processing you've  implemented  is
       sure  to  get done.  Also, if the option is delegated to a component then configure and cget are the only
       way to access it without accessing the component directly.  See DELEGATION for more information.

   HOW CAN I MAKE AN OPTION READ-ONLY?
       Define the option with -readonly yes.

       Suppose you've got an option that determines how instances of your type are constructed; it must  be  set
       at  creation  time,  after  which it's constant.  For example, a dog never changes its breed; it might or
       might not have had its shots, and if not can have them at a later time.  -breed should be read-only,  but
       -shots should not be.

              % snit::type dog {
                  option -breed -default mongrel -readonly yes
                  option -shots -default no
              }
              ::dog
              % dog fido -breed retriever
              ::fido
              % fido configure -shots yes
              % fido configure -breed terrier
              option -breed can only be set at instance creation
              %

   HOW CAN I CATCH ACCESSES TO AN OPTION'S VALUE?
       Define a -cgetmethod for the option.

   WHAT IS A -CGETMETHOD?
       A  -cgetmethod  is  a  method  that's  called whenever the related option's value is queried via the cget
       instance method.  The handler can compute the option's value, retrieve it from a database, or do anything
       else you'd like it to do.

       Here's what the default behavior would look like if written using a -cgetmethod:

              snit::type dog {
                  option -color -default brown -cgetmethod GetOption

                  method GetOption {option} {
                      return $options($option)
                  }
              }

       Any  instance method can be used, provided that it takes one argument, the name of the option whose value
       is to be retrieved.

   HOW CAN I CATCH CHANGES TO AN OPTION'S VALUE?
       Define a -configuremethod for the option.

   WHAT IS A -CONFIGUREMETHOD?
       A -configuremethod is a method that's called whenever the related option is given a  new  value  via  the
       configure or configurelist instance methods. The method can pass the value on to some other object, store
       it in a database, or do anything else you'd like it to do.

       Here's what the default configuration behavior would look like if written using a -configuremethod:

              snit::type dog {
                  option -color -default brown -configuremethod SetOption

                  method SetOption {option value} {
                      set options($option) $value
                  }
              }

       Any instance method can be used, provided that it takes two arguments, the name of the option and the new
       value.

       Note  that  if  your  method  doesn't  store  the value in the options array, the options array won't get
       updated.

   HOW CAN I VALIDATE AN OPTION'S VALUE?
       Define a -validatemethod.

   WHAT IS A -VALIDATEMETHOD?
       A -validatemethod is a method that's called whenever the related option is given  a  new  value  via  the
       configure  or  configurelist instance methods.  It's the method's responsibility to determine whether the
       new value is valid, and throw an error if it isn't.  The -validatemethod, if any, is  called  before  the
       value is stored in the options array; in particular, it's called before the -configuremethod, if any.

       For  example, suppose an option always takes a Boolean value.  You can ensure that the value is in fact a
       valid Boolean like this:

              % snit::type dog {
                  option -shots -default no -validatemethod BooleanOption

                  method BooleanOption {option value} {
                      if {![string is boolean -strict $value]} {
                          error "expected a boolean value, got \"$value\""
                      }
                  }
              }
              ::dog
              % dog fido
              % fido configure -shots yes
              % fido configure -shots NotABooleanValue
              expected a boolean value, got "NotABooleanValue"
              %

       Note that the same -validatemethod can be used to validate any number of boolean options.

       Any method can be a -validatemethod provided that it takes two arguments, the option  name  and  the  new
       option value.

TYPE VARIABLES

   WHAT IS A TYPE VARIABLE?
       A  type variable is a private variable associated with a Snit type rather than with a particular instance
       of the type.  In C++ and Java, the term static member  variable  is  used  for  the  same  notion.   Type
       variables can be scalars or arrays.

   HOW IS A SCALAR TYPE VARIABLE DEFINED?
       Scalar  type  variables  are  defined  in  the type definition using the typevariable statement.  You can
       simply name it, or you can initialize it with a value:

              snit::type mytype {
                  # Define variable "greeting" and initialize it with "Howdy!"
                  typevariable greeting "Howdy!"
              }

       Every object of type mytype now has access to a single variable called greeting.

   HOW IS AN ARRAY-VALUED TYPE VARIABLE DEFINED?
       Array-valued type variables are also defined using the typevariable command; to initialize them,  include
       the -array option:

              snit::type mytype {
                  # Define typearray variable "greetings"
                  typevariable greetings -array {
                      formal "Good Evening"
                      casual "Howdy!"
                  }
              }

   WHAT HAPPENS IF I DON'T INITIALIZE A TYPE VARIABLE?
       Variables  do not really exist until they are given values.  If you do not initialize a variable when you
       define it, then you must be sure to assign a value to it  (in  the  type  constructor,  say)  before  you
       reference it.

   ARE THERE ANY LIMITATIONS ON TYPE VARIABLE NAMES?
       Type variable names have the same restrictions as the names of INSTANCE VARIABLES do.

   DO I NEED TO DECLARE MY TYPE VARIABLES IN MY METHODS?
       No.  Once  you've  defined  a type variable in the type definition, it can be used in INSTANCE METHODS or
       TYPE METHODS without declaration.  This  differs  from  normal  Tcl  practice,  in  which  all  non-local
       variables in a proc need to be declared.

       Type  variables  are subject to the same speed/readability tradeoffs as instance variables; see Do I need
       to declare my instance variables in my methods?

   HOW DO I PASS A TYPE VARIABLE'S NAME TO ANOTHER OBJECT?
       In Tk, it's common to pass a widget a variable name; for example, Tk label widgets have  a  -textvariable
       option  which names the variable which will contain the widget's text.  This allows the program to update
       the label's value just by assigning a new value to the variable.

       If you naively pass a type variable name to the label widget, you'll be confused by the result;  Tk  will
       assume  that  the  name names a global variable.  Instead, you need to provide a fully-qualified variable
       name.  From within an instance method or a constructor, you can fully qualify the  type  variable's  name
       using the mytypevar command:

              snit::widget mywidget {
                  typevariable labeltext ""

                  constructor {args} {
                      # ...

                      label $win.label -textvariable [mytypevar labeltext]

                      # ...
                  }
              }

   HOW DO I MAKE A TYPE VARIABLE PUBLIC?
       There are two ways to do this.  The preferred way is to write a pair of TYPE METHODS to set and query the
       type variable's value.

       Type variables are stored in the type's namespace, which has the same name as the type itself.  Thus, you
       can also publicize the type variable's name in your documentation so that clients can access it directly.
       For example,

              snit::type mytype {
                  typevariable myvariable
              }

              set ::mytype::myvariable "New Value"

TYPE METHODS

   WHAT IS A TYPE METHOD?
       A type method is a procedure associated with the type itself rather than with any  specific  instance  of
       the type, and called as a subcommand of the type command.

   HOW DO I DEFINE A TYPE METHOD?
       Type methods are defined in the type definition using the typemethod statement:

              snit::type dog {
                  # List of pedigreed dogs
                  typevariable pedigreed

                  typemethod pedigreedDogs {} {
                      return $pedigreed
                  }
              }

       Suppose  the  dog  type maintains a list of the names of the dogs that have pedigrees.  The pedigreedDogs
       type method returns this list.

       The typemethod statement looks just like a normal Tcl proc,  except  that  it  appears  in  a  snit::type
       definition.   Notice  that  every  type  method gets an implicit argument called type, which contains the
       fully-qualified type name.

   HOW DOES A CLIENT CALL A TYPE METHOD?
       The type method name becomes a subcommand  of  the  type's  command.   For  example,  assuming  that  the
       constructor adds each pedigreed dog to the list of pedigreedDogs,

              snit::type dog {
                  option -pedigreed 0

                  # List of pedigreed dogs
                  typevariable pedigreed

                  typemethod pedigreedDogs {} {
                      return $pedigreed
                  }

                  # ...
              }

              dog spot -pedigreed 1
              dog fido

              foreach dog [dog pedigreedDogs] { ... }

   ARE THERE ANY LIMITATIONS ON TYPE METHOD NAMES?
       Not really, so long as you avoid the standard type method names: create, destroy, and info.

   HOW DO I MAKE A TYPE METHOD PRIVATE?
       It's sometimes useful to define private type methods, that is, type methods intended to be called only by
       other type or instance methods of the same object.

       Snit doesn't implement any access control on type methods; by convention, the  names  of  public  methods
       begin with a lower-case letter, and the names of private methods begin with an upper-case letter.

       Alternatively, a Snit proc can be used as a private type method; see PROCS.

   ARE THERE ANY LIMITATIONS ON TYPE METHOD ARGUMENTS?
       Method  argument  lists  are  defined  just  like normal Tcl proc argument lists; in particular, they can
       include arguments with default values and the args argument.

       However, every type method is called with an implicit argument called type that contains the name of  the
       type  command.   In  addition,  type  methods should by convention avoid using the names of the arguments
       implicitly defined for INSTANCE METHODS.

   HOW DOES AN INSTANCE OR TYPE METHOD CALL A TYPE METHOD?
       If an instance or type method needs to call a type method, it should use $type to do so:

              snit::type dog {

                  typemethod pedigreedDogs {} { ... }

                  typemethod printPedigrees {} {
                      foreach obj [$type pedigreedDogs] { ... }
                  }
              }

   HOW DO I PASS A TYPE METHOD AS A CALLBACK?
       It's common in Tcl to pass a snippet of code to another object, for it  to  call  later.   Because  types
       cannot  be  renamed, you can just use the type name, or, if the callback is registered from within a type
       method, type.  For example, suppose we want to print a list of pedigreed dogs when a Tk button is pushed:

              button .btn -text "Pedigrees" -command [list dog printPedigrees]
              pack .btn

       Alternatively, from a method or type method you can use the mytypemethod command, just as you  would  use
       mymethod to define a callback command for INSTANCE METHODS.

   CAN TYPE METHODS BE HIERARCHICAL?
       Yes,  you  can  define  hierarchical  type  methods  in  just the same way as you can define hierarchical
       instance methods.  See INSTANCE METHODS for more.

PROCS

   WHAT IS A PROC?
       A Snit proc is really just a Tcl proc defined within the type's namespace.  You can use procs for private
       code that isn't related to any particular instance.

   HOW DO I DEFINE A PROC?
       Procs are defined by including a proc statement in the type definition:

              snit::type mytype {
                  # Pops and returns the first item from the list stored in the
                  # listvar, updating the listvar
                 proc pop {listvar} { ... }

                 # ...
              }

   ARE THERE ANY LIMITATIONS ON PROC NAMES?
       Any  name  can  be used, so long as it does not begin with Snit_; names beginning with Snit_ are reserved
       for Snit's own use.  However, the wise programmer will avoid proc names (set, list, if, etc.) that  would
       shadow standard Tcl command names.

       proc  names, being private, should begin with a capital letter according to convention; however, as there
       are typically no public procs in the type's namespace it doesn't matter much either way.

   HOW DOES A METHOD CALL A PROC?
       Just like it calls any Tcl command.  For example,

              snit::type mytype {
                  # Pops and returns the first item from the list stored in the
                  # listvar, updating the listvar
                  proc pop {listvar} { ... }

                  variable requestQueue {}

                  # Get one request from the queue and process it.
                  method processRequest {} {
                      set req [pop requestQueue]
                  }
              }

   HOW CAN I PASS A PROC TO ANOTHER OBJECT AS A CALLBACK?
       The myproc command returns a callback command for the proc, just as mymethod does for a method.

TYPE CONSTRUCTORS

   WHAT IS A TYPE CONSTRUCTOR?
       A type constructor is a body of code that initializes the type as a  whole,  rather  like  a  C++  static
       initializer.  The body of a type constructor is executed once when the type is defined, and never again.

       A type can have at most one type constructor.

   HOW DO I DEFINE A TYPE CONSTRUCTOR?
       A  type  constructor  is  defined  by  using  the  typeconstructor statement in the type definition.  For
       example, suppose the type uses an array-valued type variable as a look-up table, and the  values  in  the
       array have to be computed at start-up.

              % snit::type mytype {
                  typevariable lookupTable

                  typeconstructor {
                      array set lookupTable {key value...}
                  }
              }

CONSTRUCTORS

   WHAT IS A CONSTRUCTOR?
       In  object-oriented  programming,  an  object's  constructor  is  responsible for initializing the object
       completely at creation time. The constructor receives the  list  of  options  passed  to  the  snit::type
       command's  create  method  and  can  then  do  whatever  it likes.  That might include computing instance
       variable values, reading data from files, creating other objects, updating type and  instance  variables,
       and so forth.

       The constructor's return value is ignored (unless it's an error, of course).

   HOW DO I DEFINE A CONSTRUCTOR?
       A  constructor  is  defined by using the constructor statement in the type definition.  Suppose that it's
       desired to keep a list of all pedigreed dogs.  The  list  can  be  maintained  in  a  type  variable  and
       retrieved by a type method.  Whenever a dog is created, it can add itself to the list--provided that it's
       registered with the American Kennel Club.

              % snit::type dog {
                  option -akc 0

                  typevariable akcList {}

                  constructor {args} {
                      $self configurelist $args

                      if {$options(-akc)} {
                          lappend akcList $self
                      }
                  }

                  typemethod akclist {} {
                      return $akcList
                  }
              }
              ::dog
              % dog spot -akc 1
              ::spot
              % dog fido
              ::fido
              % dog akclist
              ::spot
              %

   WHAT DOES THE DEFAULT CONSTRUCTOR DO?
       If you don't provide a constructor explicitly, you get the default constructor, which is identical to the
       explicitly-defined constructor shown here:

              snit::type dog {
                  constructor {args} {
                      $self configurelist $args
                  }
              }

       When  the constructor is called, args will be set to the list of arguments that follow the object's name.
       The constructor is allowed to interpret this list any way it chooses; the normal convention is to  assume
       that  it's  a list of option names and values, as shown in the example above.  If you simply want to save
       the option values, you should use the configurelist method, as shown.

   CAN I CHOOSE A DIFFERENT SET OF ARGUMENTS FOR THE CONSTRUCTOR?
       Yes, you can.  For example, suppose we wanted to be sure that the breed was explicitly stated  for  every
       dog at creation time, and couldn't be changed thereafter.  One way to do that is as follows:

              % snit::type dog {
                  variable breed

                  option -color brown
                  option -akc 0

                  constructor {theBreed args} {
                      set breed $theBreed
                      $self configurelist $args
                  }

                  method breed {} { return $breed }
              }
              ::dog
              % dog spot dalmatian -color spotted -akc 1
              ::spot
              % spot breed
              dalmatian

       The  drawback  is that this syntax is non-standard, and may limit the compatibility of your new type with
       other people's code.  For example, Snit assumes that it can create COMPONENTS using the standard creation
       syntax.

   ARE THERE ANY LIMITATIONS ON CONSTRUCTOR ARGUMENTS?
       Constructor  argument  lists  are  subject  to  the same limitations as those on instance method argument
       lists.  It has the same implicit arguments, and can contain default values and the args argument.

   IS THERE ANYTHING SPECIAL ABOUT WRITING THE CONSTRUCTOR?
       Yes.  Writing the constructor can be tricky if you're delegating options to  components,  and  there  are
       specific  issues  relating  to  snit::widgets  and snit::widgetadaptors.  See DELEGATION, WIDGETS, WIDGET
       ADAPTORS, and THE TK OPTION DATABASE.

DESTRUCTORS

   WHAT IS A DESTRUCTOR?
       A destructor is a special kind of method that's called when an object is destroyed.  It's responsible for
       doing  any  necessary  clean-up  when  the object goes away: destroying COMPONENTS, closing files, and so
       forth.

   HOW DO I DEFINE A DESTRUCTOR?
       Destructors are defined by using the destructor statement in the type definition.

       Suppose we're maintaining a list of pedigreed dogs; then we'll want to remove dogs from it when they  are
       destroyed.

              snit::type dog {
                  option -akc 0

                  typevariable akcList {}

                  constructor {args} {
                      $self configurelist $args

                      if {$options(-akc)} {
                          lappend akcList $self
                      }
                  }

                  destructor {
                      set ndx [lsearch $akcList $self]

                      if {$ndx != -1} {
                          set akcList [lreplace $akcList $ndx $ndx]
                      }
                  }

                  typemethod akclist {} {
                      return $akcList
                  }
              }

   ARE THERE ANY LIMITATIONS ON DESTRUCTOR ARGUMENTS?
       Yes; a destructor has no explicit arguments.

   WHAT IMPLICIT ARGUMENTS ARE PASSED TO THE DESTRUCTOR?
       The  destructor  gets the same implicit arguments that are passed to INSTANCE METHODS: type, selfns, win,
       and self.

   MUST COMPONENTS BE DESTROYED EXPLICITLY?
       Yes and no.

       Any Tk widgets created by a snit::widget or snit::widgetadaptor will be  destroyed  automatically  by  Tk
       when the megawidget is destroyed, in keeping with normal Tk behavior (destroying a parent widget destroys
       the whole tree).

       Components of normal snit::types, on the other hand, are never  destroyed  automatically,  nor  are  non-
       widget  components  of  Snit megawidgets.  If your object creates them in its constructor, then it should
       generally destroy them in its destructor.

   IS THERE ANY SPECIAL ABOUT WRITING A DESTRUCTOR?
       Yes.  If an object's constructor throws an error, the object's destructor will be  called  to  clean  up;
       this  means  that the object might not be completely constructed when the destructor is called.  This can
       cause the destructor to throw its own error; the result is usually misleading, confusing, and  unhelpful.
       Consequently, it's important to write your destructor so that it's fail-safe.

       For  example,  a dog might create a tail component; the component will need to be destroyed.  But suppose
       there's an error while processing the creation options--the destructor will be called, and there will  be
       no  tail  to destroy.  The simplest solution is generally to catch and ignore any errors while destroying
       components.

              snit::type dog {
                  component tail

                  constructor {args} {
                      $self configurelist $args

                      set tail [tail %AUTO%]
                  }

                  destructor {
                      catch {$tail destroy}
                  }
              }

COMPONENTS

   WHAT IS A COMPONENT?
       Often an object will create and manage a number of other objects.  A Snit megawidget, for  example,  will
       often  create a number of Tk widgets.  These objects are part of the main object; it is composed of them,
       so they are called components of the object.

       But Snit also has a more precise meaning for COMPONENT.  The  components  of  a  Snit  object  are  those
       objects  to  which  methods  or  options  can  be  delegated.  (See DELEGATION for more information about
       delegation.)

   HOW DO I DECLARE A COMPONENT?
       First, you must decide what role a component plays within your object, and give the role a  name.   Then,
       you  declare  the  component  using  its  role name and the component statement.  The component statement
       declares an instance variable which is used to store the component's command name when the  component  is
       created.

       For example, suppose your dog object creates a tail object (the better to wag with, no doubt):

              snit::type dog {
                  component mytail

                  constructor {args} {
                      # Create and save the component's command
                      set mytail [tail %AUTO% -partof $self]
                      $self configurelist $args
                  }

                  method wag {} {
                      $mytail wag
                  }
              }

       As  shown here, it doesn't matter what the tail object's real name is; the dog object refers to it by its
       component name.

       The above example shows one way to delegate the wag method to the mytail component; see DELEGATION for an
       easier way.

   HOW IS A COMPONENT NAMED?
       A  component  has  two names.  The first name is that of the component variable; this represents the role
       the component object plays within the Snit object.  This is the component name proper, and  is  the  name
       used  to  refer  to  the component within Snit code.  The second name is the name of the actual component
       object created by the Snit object's constructor.  This second name is always a Tcl command name,  and  is
       referred to as the component's object name.

       In the example in the previous question, the component name is mytail; the mytail component's object name
       is chosen automatically by Snit since %AUTO% was used when the component object was created.

   ARE THERE ANY LIMITATIONS ON COMPONENT NAMES?
       Yes.  snit::widget and snit::widgetadaptor objects have a special component called  the  hull  component;
       thus, the name hull should be used for no other purpose.

       Otherwise,  since  component  names  are  in  fact instance variable names they must follow the rules for
       INSTANCE VARIABLES.

   WHAT IS AN OWNED COMPONENT?
       An owned component is a component whose object command's lifetime is  controlled  by  the  snit::type  or
       snit::widget.

       As  stated  above,  a  component is an object to which our object can delegate methods or options.  Under
       this definition, our object will usually create its component objects, but not necessarily.  Consider the
       following: a dog object has a tail component; but tail knows that it's part of the dog:

              snit::type dog {
                  component mytail

                  constructor {args} {
                      set mytail [tail %AUTO% -partof $self]
                      $self configurelist $args
                  }

                  destructor {
                      catch {$mytail destroy}
                  }

                  delegate method wagtail to mytail as wag

                  method bark {} {
                      return "$self barked."
                  }
              }

               snit::type tail {
                   component mydog
                   option -partof -readonly yes

                   constructor {args} {
                       $self configurelist $args
                       set mydog $options(-partof)
                   }

                   method wag {} {
                       return "Wag, wag."
                   }

                   method pull {} {
                       $mydog bark
                   }
               }

       Thus,  if  you  ask  a dog to wag its tail, it tells its tail to wag; and if you pull the dog's tail, the
       tail tells the dog to bark.  In this scenario, the tail is a component of the  dog,  and  the  dog  is  a
       component of the tail, but the dog owns the tail and not the other way around.

   WHAT DOES THE INSTALL COMMAND DO?
       The  install  command creates an owned component using a specified command, and assigns the result to the
       component's instance variable.  For example:

              snit::type dog {
                  component mytail

                  constructor {args} {
                      # set mytail [tail %AUTO% -partof $self]
                      install mytail using tail %AUTO% -partof $self
                      $self configurelist $args
                  }
              }

       In a snit::type's code, the install command shown above is equivalent to the set  mytail  command  that's
       commented  out.   In  a  snit::widget's or snit::widgetadaptor's, code, however, the install command also
       queries THE TK OPTION DATABASE and initializes the new component's options accordingly.  For consistency,
       it's a good idea to get in the habit of using install for all owned components.

   MUST OWNED COMPONENTS BE CREATED IN THE CONSTRUCTOR?
       No,  not  necessarily.   In  fact, there's no reason why an object can't destroy and recreate a component
       multiple times over its own lifetime.

   ARE THERE ANY LIMITATIONS ON COMPONENT OBJECT NAMES?
       Yes.

       Component objects which are Tk widgets or megawidgets must have valid Tk window names.

       Component objects which are not widgets or megawidgets must have  fully-qualified  command  names,  i.e.,
       names  which include the full namespace of the command.  Note that Snit always creates objects with fully
       qualified names.

       Next, the object names of components and owned by your object must be unique.  This  is  no  problem  for
       widget components, since widget names are always unique; but consider the following code:

              snit::type tail { ... }

              snit::type dog {
                  delegate method wag to mytail

                  constructor {} {
                      install mytail using tail mytail
                  }
              }

       This  code  uses  the component name, mytail, as the component object name.  This is not good, and here's
       why: Snit instance code executes in the Snit type's namespace.  In this case,  the  mytail  component  is
       created in the ::dog:: namespace, and will thus have the name ::dog::mytail.

       Now,  suppose  you  create  two dogs.  Both dogs will attempt to create a tail called ::dog::mytail.  The
       first will succeed, and the second will fail, since Snit won't let you create an object if  its  name  is
       already a command.  Here are two ways to avoid this situation:

       First, if the component type is a snit::type you can specify %AUTO% as its name, and be guaranteed to get
       a unique name.  This is the safest thing to do:

                  install mytail using tail %AUTO%

       If the component type isn't a snit::type you can create the component in the object's instance namespace:

                  install mytail using tail ${selfns}::mytail

       Make sure you pick a unique name within the instance namespace.

   MUST I DESTROY THE COMPONENTS I OWN?
       That depends.  When a parent widget is destroyed, all child widgets are destroyed automatically. Thus, if
       your  object  is  a snit::widget or snit::widgetadaptor you don't need to destroy any components that are
       widgets, because they will generally be children or descendants of your megawidget.

       If your object is an instance of snit::type, though, none of  its  owned  components  will  be  destroyed
       automatically,  nor will be non-widget components of a snit::widget be destroyed automatically.  All such
       owned components must be destroyed explicitly, or they won't be destroyed at all.

   CAN I EXPOSE A COMPONENT'S OBJECT COMMAND AS PART OF MY INTERFACE?
       Yes, and there are two ways to do it.  The most appropriate way is usually to use DELEGATION.  Delegation
       allows  you to pass the options and methods you specify along to particular components.  This effectively
       hides the components from the users of your type, and ensures good encapsulation.

       However, there are times when it's appropriate, not to mention simpler, just to make the entire component
       part of your type's public interface.

   HOW DO I EXPOSE A COMPONENT'S OBJECT COMMAND?
       When  you  declare  the  component,  specify the component statement's -public option.  The value of this
       option is the name of a method which will be delegated to your component's object command.

       For example, supposed you've written a combobox megawidget which owns a listbox widget, and you  want  to
       make the listbox's entire interface public.  You can do it like this:

              snit::widget combobox {
                   component listbox -public listbox

                   constructor {args} {
                       install listbox using listbox $win.listbox ....
                   }
              }

              combobox .mycombo
              .mycombo listbox configure -width 30

       Your  comobox  widget,  .mycombo,  now  has a listbox method which has all of the same subcommands as the
       listbox widget itself.  Thus, the above code sets the listbox component's width to 30.

       Usually you'll let the method name be the same as the component name; however, you can name  it  anything
       you like.

TYPE COMPONENTS

   WHAT IS A TYPE COMPONENT?
       A  type  component  is a component that belongs to the type itself instead of to a particular instance of
       the type.  The relationship between components and type  components  is  the  same  as  the  relationship
       between  INSTANCE  VARIABLES and TYPE VARIABLES.  Both INSTANCE METHODS and TYPE METHODS can be delegated
       to type components.

       Once you understand COMPONENTS and DELEGATION, type components are just more of the same.

   HOW DO I DECLARE A TYPE COMPONENT?
       Declare a type component using the typecomponent statement.  It takes  the  same  options  (-inherit  and
       -public) as the component statement does, and defines a type variable to hold the type component's object
       command.

       Suppose in your model you've got many dogs, but only one veterinarian.  You might make the veterinarian a
       type component.

              snit::type veterinarian { ... }

              snit::type dog {
                  typecomponent vet

                  # ...
              }

   HOW DO I INSTALL A TYPE COMPONENT?
       Just  use  the set command to assign the component's object command to the type component.  Because types
       (even snit::widget types) are not widgets, and do not have options anyway,  the  extra  features  of  the
       install command are not needed.

       You'll usually install type components in the type constructor, as shown here:

              snit::type veterinarian { ... }

              snit::type dog {
                  typecomponent vet

                  typeconstructor {
                      set vet [veterinarian %AUTO%]
                  }
              }

   ARE THERE ANY LIMITATIONS ON TYPE COMPONENT NAMES?
       Yes, the same as on INSTANCE VARIABLES, TYPE VARIABLES, and normal COMPONENTS.

DELEGATION

   WHAT IS DELEGATION?
       Delegation,  simply  put,  is  when you pass a task you've been given to one of your assistants.  (You do
       have assistants, don't you?)  Snit objects can do the same thing.  The following example shows one way in
       which the dog object can delegate its wag method and its -taillength option to its tail component.

              snit::type dog {
                  variable mytail

                  option -taillength -configuremethod SetTailOption -cgetmethod GetTailOption

                  method SetTailOption {option value} {
                       $mytail configure $option $value
                  }

                  method GetTailOption {option} {
                       $mytail cget $option
                  }

                  method wag {} {
                      $mytail wag
                  }

                  constructor {args} {
                      install mytail using tail %AUTO% -partof $self
                      $self configurelist $args
                  }

              }

       This  is  the  hard  way  to  do  it, by it demonstrates what delegation is all about.  See the following
       answers for the easy way to do it.

       Note that the constructor calls the configurelist  method  after  it  creates  its  tail;  otherwise,  if
       -taillength appeared in the list of args we'd get an error.

   HOW CAN I DELEGATE A METHOD TO A COMPONENT OBJECT?
       Delegation occurs frequently enough that Snit makes it easy. Any method can be delegated to any component
       or type component by placing a single delegate statement in the type  definition.   (See  COMPONENTS  and
       TYPE COMPONENTS for more information about component names.)

       For example, here's a much better way to delegate the dog object's wag method:

              % snit::type dog {
                  delegate method wag to mytail

                  constructor {} {
                      install mytail using tail %AUTO%
                  }
              }
              ::dog
              % snit::type tail {
                  method wag {} { return "Wag, wag, wag."}
              }
              ::tail
              % dog spot
              ::spot
              % spot wag
              Wag, wag, wag.

       This  code  has the same effect as the code shown under the previous question: when a dog's wag method is
       called, the call and its arguments are passed along automatically to the tail object.

       Note that when a component is mentioned in a delegate statement, the  component's  instance  variable  is
       defined  implicitly.   However,  it's  still  good  practice to declare it explicitly using the component
       statement.

       Note also that you can define a method name using the method  statement,  or  you  can  define  it  using
       delegate; you can't do both.

   CAN I DELEGATE TO A METHOD WITH A DIFFERENT NAME?
       Suppose  you wanted to delegate the dog's wagtail method to the tail's wag method.  After all you wag the
       tail, not the dog.  It's easily done:

              snit::type dog {
                  delegate method wagtail to mytail as wag

                  constructor {args} {
                      install mytail using tail %AUTO% -partof $self
                      $self configurelist $args
                  }
              }

   CAN I DELEGATE TO A METHOD WITH ADDITIONAL ARGUMENTS?
       Suppose the tail's wag method takes as an argument the number of times the tail should  be  wagged.   You
       want  to  delegate  the dog's wagtail method to the tail's wag method, specifying that the tail should be
       wagged exactly three times.  This is easily done, too:

              snit::type dog {
                  delegate method wagtail to mytail as {wag 3}
                  # ...
              }

              snit::type tail {
                  method wag {count} {
                      return [string repeat "Wag " $count]
                  }
                  # ...
              }

   CAN I DELEGATE A METHOD TO SOMETHING OTHER THAN AN OBJECT?
       Normal method delegation assumes that you're delegating a method (a subcommand of an object command) to a
       method of another object (a subcommand of a different object command).  But not all Tcl objects follow Tk
       conventions, and not everything you'd to which you'd like to delegate a method is  necessary  an  object.
       Consequently, Snit makes it easy to delegate a method to pretty much anything you like using the delegate
       statement's using clause.

       Suppose your dog simulation stores dogs in a database, each dog as a single  record.   The  database  API
       you're  using  provides  a  number  of commands to manage records; each takes the record ID (a string you
       choose) as its first argument.  For example, saverec saves a record.  If you let the  record  ID  be  the
       name of the dog object, you can delegate the dog's save method to the saverec command as follows:

              snit::type dog {
                  delegate method save using {saverec %s}
              }

       The  %s  is  replaced with the instance name when the save method is called; any additional arguments are
       the appended to the resulting command.

       The using clause understands a number of other %-conversions; in addition to the instance name,  you  can
       substitute  in  the method name (%m), the type name (%t), the instance namespace (%n), the Tk window name
       (%w), and, if a component or typecomponent name was given in  the  delegate  statement,  the  component's
       object command (%c).

   HOW CAN I DELEGATE A METHOD TO A TYPE COMPONENT OBJECT?
       Just  exactly  as  you would to a component object.  The delegate method statement accepts both component
       and type component names in its to clause.

   HOW CAN I DELEGATE A TYPE METHOD TO A TYPE COMPONENT OBJECT?
       Use the delegate typemethod statement.  It works like delegate method, with these differences: first,  it
       defines  a type method instead of an instance method; second, the using clause ignores the %s, %n, and %w
       %-conversions.

       Naturally, you can't delegate a type method to an instance component...Snit wouldn't know which  instance
       should receive it.

   HOW CAN I DELEGATE AN OPTION TO A COMPONENT OBJECT?
       The  first  question in this section (see DELEGATION) shows one way to delegate an option to a component;
       but this pattern occurs often enough that Snit makes it easy.  For  example,  every  tail  object  has  a
       -length option; we want to allow the creator of a dog object to set the tail's length.  We can do this:

              % snit::type dog {
                  delegate option -length to mytail

                  constructor {args} {
                      install mytail using tail %AUTO% -partof $self
                      $self configurelist $args
                  }
              }
              ::dog
              % snit::type tail {
                  option -partof
                  option -length 5
              }
              ::tail
              % dog spot -length 7
              ::spot
              % spot cget -length
              7

       This  produces  nearly  the  same  result  as  the -configuremethod and -cgetmethod shown under the first
       question in this section: whenever a dog object's -length option is set or retrieved, the underlying tail
       object's option is set or retrieved in turn.

       Note  that you can define an option name using the option statement, or you can define it using delegate;
       you can't do both.

   CAN I DELEGATE TO AN OPTION WITH A DIFFERENT NAME?
       In the previous answer we delegated the dog's -length option down to  its  tail.   This  is,  of  course,
       wrong.   The  dog has a length, and the tail has a length, and they are different.  What we'd really like
       to do is give the dog a -taillength option, but delegate it to the tail's -length option:

              snit::type dog {
                  delegate option -taillength to mytail as -length

                  constructor {args} {
                      set mytail [tail %AUTO% -partof $self]
                      $self configurelist $args
                  }
              }

   HOW CAN I DELEGATE ANY UNRECOGNIZED METHOD OR OPTION TO A COMPONENT OBJECT?
       It may happen that a Snit object gets most of its behavior  from  one  of  its  components.   This  often
       happens  with  snit::widgetadaptors, for example, where we wish to slightly the modify the behavior of an
       existing widget.  To carry on with our dog example, however, suppose that we  have  a  snit::type  called
       animal  that  implements  a variety of animal behaviors--moving, eating, sleeping, and so forth.  We want
       our dog objects to inherit these same behaviors, while adding dog-like behaviors of its own.  Here's  how
       we  can  give  a dog methods and options of its own while delegating all other methods and options to its
       animal component:

              snit::type dog {
                  delegate option * to animal
                  delegate method * to animal

                  option -akc 0

                  constructor {args} {
                      install animal using animal %AUTO% -name $self
                      $self configurelist $args
                  }

                  method wag {} {
                      return "$self wags its tail"
                  }
              }

       That's it.  A dog is now an animal that has a -akc option and can wag its tail.

       Note that we don't need to specify the full list of  method  names  or  option  names  that  animal  will
       receive.   It  gets anything dog doesn't recognize--and if it doesn't recognize it either, it will simply
       throw an error, just as it should.

       You can also delegate all unknown type methods to a type component using delegate typemethod *.

   HOW CAN I DELEGATE ALL BUT CERTAIN METHODS OR OPTIONS TO A COMPONENT?
       In the previous answer, we said that every dog is an animal by delegating all unknown methods and options
       to  the  animal  component.  But  what  if  the animal type has some methods or options that we'd like to
       suppress?

       One solution is to explicitly delegate all the options and methods, and forgo the convenience of delegate
       method  *  and  delegate  option *.  But if we wish to suppress only a few options or methods, there's an
       easier way:

              snit::type dog {
                  delegate option * to animal except -numlegs
                  delegate method * to animal except {fly climb}

                  # ...

                  constructor {args} {
                      install animal using animal %AUTO% -name $self -numlegs 4
                      $self configurelist $args
                  }

                  # ...
              }

       Dogs have four legs, so we specify that explicitly when we create the animal  component,  and  explicitly
       exclude  -numlegs  from  the  set of delegated options.  Similarly, dogs can neither fly nor climb, so we
       exclude those animal methods as shown.

   CAN A HIERARCHICAL METHOD BE DELEGATED?
       Yes; just specify multiple words in the delegated method's name:

              snit::type tail {
                  method wag {} {return "Wag, wag"}
                  method droop {} {return "Droop, droop"}
              }

              snit::type dog {
                  delegate method {tail wag} to mytail
                  delegate method {tail droop} to mytail

                  # ...

                  constructor {args} {
                      install mytail using tail %AUTO%
                      $self configurelist $args
                  }

                  # ...
              }

       Unrecognized hierarchical methods can also be delegated; the following code delegates all subcommands  of
       the "tail" method to the "mytail" component:

              snit::type dog {
                  delegate method {tail *} to mytail

                  # ...
              }

WIDGETS

   WHAT IS A SNIT::WIDGET?
       A  snit::widget  is  the  Snit  version  of what Tcl programmers usually call a megawidget: a widget-like
       object usually consisting of one or more Tk widgets all contained within a Tk frame.

       A snit::widget is also a special kind of snit::type.  Just about everything in this FAQ list that relates
       to snit::types also applies to snit::widgets.

   HOW DO I DEFINE A SNIT::WIDGET?
       snit::widgets  are  defined  using  the  snit::widget  command,  just  as  snit::types are defined by the
       snit::type command.

       The body of the definition can contain all of the same kinds of statements, plus a couple of others which
       will be mentioned below.

   HOW DO SNIT::WIDGETS DIFFER FROM SNIT::TYPES?
       •      The  name of an instance of a snit::type can be any valid Tcl command name, in any namespace.  The
              name of an instance of a snit::widget must be a valid Tk widget name, and its parent  widget  must
              already exist.

       •      An  instance  of  a  snit::type  can  be  destroyed by calling its destroy method.  Instances of a
              snit::widget have no destroy method; use the Tk destroy command instead.

       •      Every instance of a snit::widget has one predefined component called its hull component.  The hull
              is  usually  a  Tk frame or toplevel widget; any other widgets created as part of the snit::widget
              will usually be contained within the hull.

       •      snit::widgets can have their options receive default values from THE TK OPTION DATABASE.

   WHAT IS A HULL COMPONENT?
       Snit can't create a Tk widget object; only Tk can do that.  Thus, every instance of a  snit::widget  must
       be  wrapped  around  a  genuine Tk widget; this Tk widget is called the hull component.  Snit effectively
       piggybacks the behavior you define (methods, options, and so forth) on top of the hull component so  that
       the whole thing behaves like a standard Tk widget.

       For snit::widgets the hull component must be a Tk widget that defines the -class option.

       snit::widgetadaptors differ from snit::widgets chiefly in that any kind of widget can be used as the hull
       component; see WIDGET ADAPTORS.

   HOW CAN I SET THE HULL TYPE FOR A SNIT::WIDGET?
       A snit::widget's hull component will usually be a Tk frame widget; however, it may be any Tk widget  that
       defines  the -class option.  You can explicitly choose the hull type you prefer by including the hulltype
       command in the widget definition:

              snit::widget mytoplevel {
                  hulltype toplevel

                  # ...
              }

       If no hulltype command appears, the hull will be a frame.

       By default, Snit recognizes the following hull types: the Tk widgets frame, labelframe, toplevel, and the
       Tile  widgets  ttk::frame,  ttk::labelframe,  and ttk::toplevel.  To enable the use of some other kind of
       widget as the hull type, you can lappend the widget  command  to  the  variable  snit::hulltypes  (always
       provided  the  widget defines the -class option.  For example, suppose Tk gets a new widget type called a
       prettyframe:

              lappend snit::hulltypes prettyframe

              snit::widget mywidget {
                  hulltype prettyframe

                  # ...
              }

   HOW SHOULD I NAME WIDGETS WHICH ARE COMPONENTS OF A SNIT::WIDGET?
       Every widget, whether a genuine Tk widget or a Snit megawidget, has to have a valid Tk window name.  When
       a  snit::widget  is  first  created,  its  instance  name,  self,  is  a  Tk window name; however, if the
       snit::widget is used as the hull component by a snit::widgetadaptor its instance name will be changed  to
       something  else.   For  this  reason, every snit::widget method, constructor, destructor, and so forth is
       passed another implicit argument, win, which is the window name of the megawidget.  Any  children  should
       be named using win as the root.

       Thus,  suppose you're writing a toolbar widget, a frame consisting of a number of buttons placed side-by-
       side.  It might look something like this:

              snit::widget toolbar {
                  delegate option * to hull

                  constructor {args} {
                      button $win.open -text Open -command [mymethod open]
                      button $win.save -text Save -command [mymethod save]

                      # ....

                      $self configurelist $args

                  }
              }

       See also the question on renaming objects, toward the top of this file.

WIDGET ADAPTORS

   WHAT IS A SNIT::WIDGETADAPTOR?
       A snit::widgetadaptor is a kind of snit::widget.  Whereas a snit::widget's hull is automatically  created
       and is always a Tk frame, a snit::widgetadaptor can be based on any Tk widget--or on any Snit megawidget,
       or even (with luck) on megawidgets defined using some other package.

       It's called a widget adaptor because it allows you to take an existing widget and customize its behavior.

   HOW DO I DEFINE A SNIT::WIDGETADAPTOR?
       Use the snit::widgetadaptor command.  The definition for a snit::widgetadaptor looks just like that for a
       snit::type or snit::widget, except that the constructor must create and install the hull component.

       For  example,  the  following  code  creates  a read-only text widget by the simple device of turning its
       insert and delete methods into no-ops.  Then, we define new methods, ins and del, which get delegated  to
       the  hull  component as insert and delete.  Thus, we've adapted the text widget and given it new behavior
       while still leaving it fundamentally a text widget.

              ::snit::widgetadaptor rotext {

                  constructor {args} {
                      # Create the text widget; turn off its insert cursor
                      installhull using text -insertwidth 0

                      # Apply any options passed at creation time.
                      $self configurelist $args
                  }

                  # Disable the text widget's insert and delete methods, to
                  # make this readonly.
                  method insert {args} {}
                  method delete {args} {}

                  # Enable ins and del as synonyms, so the program can insert and
                  # delete.
                  delegate method ins to hull as insert
                  delegate method del to hull as delete

                  # Pass all other methods and options to the real text widget, so
                  # that the remaining behavior is as expected.
                  delegate method * to hull
                  delegate option * to hull
              }

       The most important part  is  in  the  constructor.   Whereas  snit::widget  creates  the  hull  for  you,
       snit::widgetadaptor  cannot  --  it  doesn't  know  what kind of widget you want.  So the first thing the
       constructor does is create the hull component (a Tk text widget in this case), and then installs it using
       the installhull command.

       Note:  There  is no instance command until you create one by installing a hull component.  Any attempt to
       pass methods to $self prior to calling installhull will fail.

   CAN I ADAPT A WIDGET CREATED ELSEWHERE IN THE PROGRAM?
       Yes.

       At times, it can be convenient to adapt a pre-existing widget instead of creating your own.  For example,
       the  Bwidget  PagesManager widget manages a set of frame widgets, only one of which is visible at a time.
       The application chooses which frame is visible.  All of the These frames are created by the  PagesManager
       itself, using its add method.  It's convenient to adapt these frames to do what we'd like them to do.

       In  a  case  like  this,  the Tk widget will already exist when the snit::widgetadaptor is created.  Snit
       provides an alternate form of the installhull command for this purpose:

              snit::widgetadaptor pageadaptor {
                  constructor {args} {
                      # The widget already exists; just install it.
                      installhull $win

                      # ...
                  }
              }

   CAN I ADAPT ANOTHER MEGAWIDGET?
       Maybe. If the other megawidget is a snit::widget or snit::widgetadaptor, then yes.   If  it  isn't  then,
       again,  maybe.   You'll  have  to  try  it  and  see.   You're  most  likely  to have trouble with widget
       destruction--you have to make sure that your megawidget code receives  the  <Destroy>  event  before  the
       megawidget you're adapting does.

THE TK OPTION DATABASE

   WHAT IS THE TK OPTION DATABASE?
       The  Tk  option  database  is  a  database  of  default  option  values maintained by Tk itself; every Tk
       application has one.  The concept of the option database derives from  something  called  the  X  Windows
       resource  database; however, the option database is available in every Tk implementation, including those
       which do not use the X Windows system (e.g., Microsoft Windows).

       Full details about the Tk option  database  are  beyond  the  scope  of  this  document;  both  Practical
       Programming  in  Tcl  and Tk by Welch, Jones, and Hobbs, and Effective Tcl/Tk Programming by Harrison and
       McClennan., have good introductions to it.

       Snit is implemented so that most of the time it will simply do the right thing with respect to the option
       database, provided that the widget developer does the right thing by Snit.  The body of this section goes
       into great deal about what Snit requires.  The following is a brief statement of  the  requirements,  for
       reference.

       •      If  the  widget's  default  widget  class  is  not  what  is  desired, set it explicitly using the
              widgetclass statement in the widget definition.

       •      When defining or delegating  options,  specify  the  resource  and  class  names  explicitly  when
              necessary.

       •      Use the installhull using command to create and install the hull for snit::widgetadaptors.

       •      Use the install command to create and install all components which are widgets.

       •      Use  the  install command to create and install components which aren't widgets if you'd like them
              to receive option values from the option database.

       The interaction of Tk widgets with the option database is a complex thing; the interaction of  Snit  with
       the option database is even more so, and repays attention to detail.

   DO SNIT::TYPES USE THE TK OPTION DATABASE?
       No, they don't; querying the option database requires a Tk window name, and snit::types don't have one.

       If you create an instance of a snit::type as a component of a snit::widget or snit::widgetadaptor, on the
       other hand, and if any options are delegated to the component, and if  you  use  install  to  create  and
       install it, then the megawidget will query the option database on the snit::type's behalf.  This might or
       might not be what you want, so take care.

   WHAT IS MY SNIT::WIDGET'S WIDGET CLASS?
       Every Tk widget has a "widget class": a name that is used when adding option settings  to  the  database.
       For  Tk  widgets,  the  widget class is the same as the widget command name with an initial capital.  For
       example, the widget class of the Tk button widget is Button.

       Similarly, the widget class of a snit::widget defaults to the unqualified type name with the first letter
       capitalized.  For example, the widget class of

              snit::widget ::mylibrary::scrolledText { ... }

       is ScrolledText.

       The  widget  class  can  also  be  set explicitly using the widgetclass statement within the snit::widget
       definition:

              snit::widget ::mylibrary::scrolledText {
                  widgetclass Text

                  # ...
              }

       The above definition says that a scrolledText megawidget has the same widget class as  an  ordinary  text
       widget.   This might or might not be a good idea, depending on how the rest of the megawidget is defined,
       and how its options are delegated.

   WHAT IS MY SNIT::WIDGETADAPTOR'S WIDGET CLASS?
       The widget class of a snit::widgetadaptor is just the widget class  of  its  hull  widget;  Snit  has  no
       control over this.

       Note that the widget class can be changed only for frame and toplevel widgets, which is why these are the
       valid hull types for snit::widgets.

       Try to use snit::widgetadaptors only to make small modifications to another widget's behavior.  Then,  it
       will usually not make sense to change the widget's widget class anyway.

   WHAT ARE OPTION RESOURCE AND CLASS NAMES?
       Every  Tk  widget  option  has  three names: the option name, the resource name, and the class name.  The
       option name begins with a hyphen and is all lowercase; it's used when  creating  widgets,  and  with  the
       configure and cget commands.

       The  resource  and  class  names  are  used  to  initialize  option default values by querying the option
       database.  The resource name is usually just the option name minus the hyphen, but may contain  uppercase
       letters at word boundaries; the class name is usually just the resource name with an initial capital, but
       not always.  For example, here are the option, resource, and class  names  for  several  Tk  text  widget
       options:

                  -background         background         Background
                  -borderwidth        borderWidth        BorderWidth
                  -insertborderwidth  insertBorderWidth  BorderWidth
                  -padx               padX               Pad

       As  is  easily seen, sometimes the resource and class names can be inferred from the option name, but not
       always.

   WHAT ARE THE RESOURCE AND CLASS NAMES FOR MY MEGAWIDGET'S OPTIONS?
       For options implicitly delegated to a component using delegate option *, the  resource  and  class  names
       will be exactly those defined by the component.  The configure method returns these names, along with the
       option's default and current values:

              % snit::widget mytext {
                  delegate option * to text

                  constructor {args} {
                      install text using text .text
                      # ...
                  }

                  # ...
              }
              ::mytext
              % mytext .text
              .text
              % .text configure -padx
              -padx padX Pad 1 1
              %

       For all other options (whether locally defined or explicitly delegated), the resource and class names can
       be defined explicitly, or they can be allowed to have default values.

       By  default,  the  resource name is just the option name minus the hyphen; the the class name is just the
       option name with an initial capital letter.  For example, suppose we explicitly delegate "-padx":

              % snit::widget mytext {
                  option -myvalue 5

                  delegate option -padx to text
                  delegate option * to text

                  constructor {args} {
                      install text using text .text
                      # ...
                  }

                  # ...
              }
              ::mytext
              % mytext .text
              .text
              % .text configure -myvalue
              -myvalue myvalue Myvalue 5 5
              % .text configure -padx
              -padx padx Padx 1 1
              %

       Here the resource and class names are chosen using the default rules.  Often these rules are  sufficient,
       but  in  the  case  of "-padx" we'd most likely prefer that the option's resource and class names are the
       same as for the built-in Tk widgets.  This is easily done:

              % snit::widget mytext {
                  delegate option {-padx padX Pad} to text

                  # ...
              }
              ::mytext
              % mytext .text
              .text
              % .text configure -padx
              -padx padX Pad 1 1
              %

   HOW DOES SNIT INITIALIZE MY MEGAWIDGET'S LOCALLY-DEFINED OPTIONS?
       The option database is queried for each of the megawidget's locally-defined options, using  the  option's
       resource  and  class  name.   If  the result isn't "", then it replaces the default value given in widget
       definition.  In either case, the default can be overridden by the caller.  For example,

              option add *Mywidget.texture pebbled

              snit::widget mywidget {
                  option -texture smooth
                  # ...
              }

              mywidget .mywidget -texture greasy

       Here, -texture would normally default to "smooth", but because of the entry added to the option  database
       it  defaults  to  "pebbled".   However,  the caller has explicitly overridden the default, and so the new
       widget will be "greasy".

   HOW DOES SNIT INITIALIZE DELEGATED OPTIONS?
       That depends on whether the options are delegated to the hull, or to some other component.

   HOW DOES SNIT INITIALIZE OPTIONS DELEGATED TO THE HULL?
       A snit::widget's hull is a widget, and given that its class has been set it  is  expected  to  query  the
       option  database  for  itself.   The  only  exception  concerns  options  that are delegated to it with a
       different name.  Consider the following code:

              option add *Mywidget.borderWidth 5
              option add *Mywidget.relief sunken
              option add *Mywidget.hullbackground red
              option add *Mywidget.background green

              snit::widget mywidget {
                  delegate option -borderwidth to hull
                  delegate option -hullbackground to hull as -background
                  delegate option * to hull
                  # ...
              }

              mywidget .mywidget

              set A [.mywidget cget -relief]
              set B [.mywidget cget -hullbackground]
              set C [.mywidget cget -background]
              set D [.mywidget cget -borderwidth]

       The question is, what are the values of variables A, B, C and D?

       The value of A is "sunken".  The hull is a Tk frame which has been given the widget  class  Mywidget;  it
       will  automatically  query  the  option  database  and  pick  up this value.  Since the -relief option is
       implicitly delegated to the hull, Snit takes no action.

       The value of B is "red".  The hull will automatically pick up  the  value  "green"  for  its  -background
       option,  just  as  it picked up the -relief value.  However, Snit knows that -hullbackground is mapped to
       the hull's -background option; hence, it queries the option database for -hullbackground and  gets  "red"
       and updates the hull accordingly.

       The  value  of C is also "red", because -background is implicitly delegated to the hull; thus, retrieving
       it is the same as retrieving -hullbackground.  Note that this case is  unusual;  the  -background  option
       should  probably  have  been  excluded  using  the  delegate  statement's except clause, or (more likely)
       delegated to some other component.

       The value of D is "5", but not for the reason you think.  Note that as it is defined above, the  resource
       name  for  -borderwidth  defaults  to  borderwidth,  whereas the option database entry is borderWidth, in
       accordance with the standard Tk naming for this option.  As with -relief,  the  hull  picks  up  its  own
       -borderwidth  option before Snit does anything.  Because the option is delegated under its own name, Snit
       assumes that the correct thing has happened, and doesn't worry about it any further.  To avoid confusion,
       the -borderwidth option should have been delegated like this:

                  delegate option {-borderwidth borderWidth BorderWidth} to hull

       For snit::widgetadaptors, the case is somewhat altered.  Widget adaptors retain the widget class of their
       hull, and the hull is not created automatically by Snit.   Instead,  the  snit::widgetadaptor  must  call
       installhull in its constructor.  The normal way to do this is as follows:

              snit::widgetadaptor mywidget {
                  # ...
                  constructor {args} {
                      # ...
                      installhull using text -foreground white
                      # ...
                  }
                  # ...
              }

       In this case, the installhull command will create the hull using a command like this:

                  set hull [text $win -foreground white]

       The  hull  is  a text widget, so its widget class is Text.  Just as with snit::widget hulls, Snit assumes
       that it will pick up all of its normal option values automatically,  without  help  from  Snit.   Options
       delegated  from  a  different  name are initialized from the option database in the same way as described
       above.

       In earlier versions of Snit, snit::widgetadaptors were expected to call installhull like this:

                  installhull [text $win -foreground white]

       This form still works--but Snit will not query the option database as described above.

   HOW DOES SNIT INITIALIZE OPTIONS DELEGATED TO OTHER COMPONENTS?
       For hull components, Snit assumes that Tk will do most of the work  automatically.   Non-hull  components
       are somewhat more complicated, because they are matched against the option database twice.

       A  component  widget remains a widget still, and is therefore initialized from the option database in the
       usual way.  A text widget remains a text widget whether it is a component of a  megawidget  or  not,  and
       will be created as such.

       But then, the option database is queried for all options delegated to the component, and the component is
       initialized accordingly--provided that the install command is used to create it.

       Before option database support was added to Snit, the usual way to  create  a  component  was  to  simply
       create it in the constructor and assign its command name to the component variable:

              snit::widget mywidget {
                  delegate option -background to myComp

                  constructor {args} {
                      set myComp [text $win.text -foreground black]
                  }
              }

       The drawback of this method is that Snit has no opportunity to initialize the component properly.  Hence,
       the following approach is now used:

              snit::widget mywidget {
                  delegate option -background to myComp

                  constructor {args} {
                      install myComp using text $win.text -foreground black
                  }
              }

       The install command does the following:

       •      Builds a  list  of  the  options  explicitly  included  in  the  install  command--in  this  case,
              -foreground.

       •      Queries the option database for all options delegated explicitly to the named component.

       •      Creates  the  component using the specified command, after inserting into it a list of options and
              values read from the option database.  Thus, the explicitly included  options  (like  -foreground)
              will override anything read from the option database.

       •      If  the  widget  definition implicitly delegated options to the component using delegate option *,
              then Snit calls the newly created component's configure method to receive a list  of  all  of  the
              component's  options.   From  this  Snit  builds  a  list  of  options implicitly delegated to the
              component which were not explicitly included in the install command.  For all such  options,  Snit
              queries the option database and configures the component accordingly.

       You don't really need to know all of this; just use install to install your components, and Snit will try
       to do the right thing.

   WHAT HAPPENS IF I INSTALL A NON-WIDGET AS A COMPONENT OF WIDGET?
       A snit::type never queries the option database.  However, a snit::widget can have non-widget  components.
       And  if  options  are  delegated to those components, and if the install command is used to install those
       components, then they will be initialized from the option database just as widget components are.

       However, when used within a megawidget, install assumes that the  created  component  uses  a  reasonably
       standard widget-like creation syntax.  If it doesn't, don't use install.

ENSEMBLE COMMANDS

   WHAT IS AN ENSEMBLE COMMAND?
       An  ensemble command is a command with subcommands.  Snit objects are all ensemble commands; however, the
       term more usually refers to commands like the standard Tcl commands string, file, and clock.  In a sense,
       these are singleton objects--there's only one instance of them.

   HOW CAN I CREATE AN ENSEMBLE COMMAND USING SNIT?
       There are two ways--as a snit::type, or as an instance of a snit::type.

   HOW CAN I CREATE AN ENSEMBLE COMMAND USING AN INSTANCE OF A SNIT::TYPE?
       Define  a  type  whose  INSTANCE  METHODS  are the subcommands of your ensemble command.  Then, create an
       instance of the type with the desired name.

       For example, the following code uses DELEGATION to create a work-alike for the standard string command:

              snit::type ::mynamespace::mystringtype {
                  delegate method * to stringhandler

                  constructor {} {
                      set stringhandler string
                  }
              }

              ::mynamespace::mystringtype mystring

       We create the type in a namespace, so that the type command is hidden; then we create a  single  instance
       with the desired name-- mystring, in this case.

       This  method  has two drawbacks.  First, it leaves the type command floating about.  More seriously, your
       shiny new ensemble command will have info and destroy subcommands that you probably have no use for.  But
       read on.

   HOW CAN I CREATE AN ENSEMBLE COMMAND USING A SNIT::TYPE?
       Define a type whose TYPE METHODS are the subcommands of your ensemble command.

       For example, the following code uses DELEGATION to create a work-alike for the standard string command:

              snit::type mystring {
                  delegate typemethod * to stringhandler

                  typeconstructor {
                      set stringhandler string
                  }
              }

       Now the type command itself is your ensemble command.

       This  method  has  only  one  drawback, and though it's major, it's also surmountable.  Your new ensemble
       command will have create, info and destroy subcommands you don't want.  And worse yet, since  the  create
       method  can  be  implicit, users of your command will accidentally be creating instances of your mystring
       type if they should mispell one of the subcommands.  The command will succeed--the first time--but  won't
       do what's wanted.  This is very bad.

       The work around is to set some PRAGMAS, as shown here:

              snit::type mystring {
                  pragma -hastypeinfo    no
                  pragma -hastypedestroy no
                  pragma -hasinstances   no

                  delegate typemethod * to stringhandler

                  typeconstructor {
                      set stringhandler string
                  }
              }

       Here  we've  used the pragma statement to tell Snit that we don't want the info typemethod or the destroy
       typemethod, and that our type has no instances; this eliminates the create  typemethod  and  all  related
       code.  As a result, our ensemble command will be well-behaved, with no unexpected subcommands.

PRAGMAS

   WHAT IS A PRAGMA?
       A  pragma  is an option you can set in your type definitions that affects how the type is defined and how
       it works once it is defined.

   HOW DO I SET A PRAGMA?
       Use the pragma statement.  Each pragma is an option with a value; each time you use the pragma  statement
       you can set one or more of them.

   HOW CAN I GET RID OF THE  INFO" TYPE METHOD?"
       Set the -hastypeinfo pragma to no:

              snit::type dog {
                  pragma -hastypeinfo no
                  # ...
              }

       Snit will refrain from defining the info type method.

   HOW CAN I GET RID OF THE  DESTROY" TYPE METHOD?"
       Set the -hastypedestroy pragma to no:

              snit::type dog {
                  pragma -hastypedestroy no
                  # ...
              }

       Snit will refrain from defining the destroy type method.

   HOW CAN I GET RID OF THE  CREATE" TYPE METHOD?"
       Set the -hasinstances pragma to no:

              snit::type dog {
                  pragma -hasinstances no
                  # ...
              }

       Snit  will  refrain  from  defining  the create type method; if you call the type command with an unknown
       method name, you'll get an error instead of a new instance of the type.

       This is useful if you wish to use a snit::type to define an ensemble command  rather  than  a  type  with
       instances.

       Pragmas -hastypemethods and -hasinstances cannot both be false (or there'd be nothing left).

   HOW CAN I GET RID OF TYPE METHODS ALTOGETHER?
       Normal  Tk widget type commands don't have subcommands; all they do is create widgets--in Snit terms, the
       type command calls the create type method directly.   To  get  the  same  behavior  from  Snit,  set  the
       -hastypemethods pragma to no:

              snit::type dog {
                  pragma -hastypemethods no
                  #...
              }

              # Creates ::spot
              dog spot

              # Tries to create an instance called ::create
              dog create spot

       Pragmas -hastypemethods and -hasinstances cannot both be false (or there'd be nothing left).

   WHY CAN'T I CREATE AN OBJECT THAT REPLACES AN OLD OBJECT WITH THE SAME NAME?
       Up  until Snit 0.95, you could use any name for an instance of a snit::type, even if the name was already
       in use by some other object or command.  You could do the following, for example:

              snit::type dog { ... }

              dog proc

       You now have a new dog named "proc", which is probably not something that you really wanted to do.  As  a
       result,  Snit now throws an error if your chosen instance name names an existing command.  To restore the
       old behavior, set the -canreplace pragma to yes:

              snit::type dog {
                  pragma -canreplace yes
                  # ...
              }

   HOW CAN I MAKE MY SIMPLE TYPE RUN FASTER?
       In Snit 1.x, you can set the -simpledispatch pragma to yes.

       Snit 1.x method dispatch is both flexible and fast, but the flexibility comes with a price.  If your type
       doesn't  require  the flexibility, the -simpledispatch pragma allows you to substitute a simpler dispatch
       mechanism that runs quite a bit faster.  The limitations are these:

       •      Methods cannot be delegated.

       •      uplevel and upvar do not work as expected: the caller's scope is two levels up rather than one.

       •      The option-handling methods (cget, configure, and configurelist) are very slightly slower.

       In Snit 2.2, the -simpledispatch macro is obsolete, and ignored; all Snit 2.2 method dispatch  is  faster
       than Snit 1.x's -simpledispatch.

MACROS

   WHAT IS A MACRO?
       A  Snit  macro is nothing more than a Tcl proc that's defined in the Tcl interpreter used to compile Snit
       type definitions.

   WHAT ARE MACROS GOOD FOR?
       You can use Snit macros to define new type definition syntax, and to support conditional compilation.

   HOW DO I DO CONDITIONAL COMPILATION?
       Suppose you want your type to use a fast C extension if it's available; otherwise, you'll fallback  to  a
       slower  Tcl  implementation.  You want to define one set of methods in the first case, and another set in
       the second case.  But how can your type definition know whether the fast C extension is available or not?

       It's easily done.  Outside of any type definition, define a macro that returns  1  if  the  extension  is
       available, and 0 otherwise:

              if {$gotFastExtension} {
                  snit::macro fastcode {} {return 1}
              } else {
                  snit::macro fastcode {} {return 0}
              }

       Then, use your macro in your type definition:

              snit::type dog {

                  if {[fastcode]} {
                      # Fast methods
                      method bark {} {...}
                      method wagtail {} {...}
                  } else {
                      # Slow methods
                      method bark {} {...}
                      method wagtail {} {...}
                  }
              }

   HOW DO I DEFINE NEW TYPE DEFINITION SYNTAX?
       Use  a  macro.   For  example, your snit::widget's -background option should be propagated to a number of
       component widgets.  You could implement that like this:

              snit::widget mywidget {
                  option -background -default white -configuremethod PropagateBackground

                  method PropagateBackground {option value} {
                      $comp1 configure $option $value
                      $comp2 configure $option $value
                      $comp3 configure $option $value
                  }
              }

       For one option, this is fine; if you've got a number of options, it becomes tedious and error prone.   So
       package it as a macro:

              snit::macro propagate {option "to" components} {
                  option $option -configuremethod Propagate$option

                  set body "\n"

                  foreach comp $components {
                      append body "\$$comp configure $option \$value\n"
                  }

                  method Propagate$option {option value} $body
              }

       Then you can use it like this:

              snit::widget mywidget {
                  option -background default -white
                  option -foreground default -black

                  propagate -background to {comp1 comp2 comp3}
                  propagate -foreground to {comp1 comp2 comp3}
              }

   ARE THERE ARE RESTRICTIONS ON MACRO NAMES?
       Yes,  there  are.   You can't redefine any standard Tcl commands or Snit type definition statements.  You
       can use any other command name, including the name of a previously defined macro.

       If you're using Snit macros in your application, go ahead and name them in the global namespace, as shown
       above.   But  if  you're  using them to define types or widgets for use by others, you should define your
       macros in the same namespace as your types or widgets.  That way, they won't conflict with other people's
       macros.

       If  my  fancy  snit::widget  is  called ::mylib::mywidget, for example, then I should define my propagate
       macro as ::mylib::propagate:

              snit::macro mylib::propagate {option "to" components} { ... }

              snit::widget ::mylib::mywidget {
                  option -background default -white
                  option -foreground default -black

                  mylib::propagate -background to {comp1 comp2 comp3}
                  mylib::propagate -foreground to {comp1 comp2 comp3}
              }

BUGS, IDEAS, FEEDBACK

       This document, and the package it describes, will undoubtedly contain bugs and  other  problems.   Please
       report  such  in the category snit of the Tcllib Trackers [http://core.tcl.tk/tcllib/reportlist].  Please
       also report any ideas for enhancements you may have for either package and/or documentation.

       When proposing code changes, please provide unified diffs, i.e the output of diff -u.

       Note further that attachments are strongly preferred over inlined patches. Attachments  can  be  made  by
       going  to the Edit form of the ticket immediately after its creation, and then using the left-most button
       in the secondary navigation bar.

KEYWORDS

       BWidget, C++, Incr Tcl, adaptors, class, mega widget, object, object oriented, widget, widget adaptors

CATEGORY

       Programming tools

       Copyright (c) 2003-2006, by William H. Duquette