snitfaq(3)



snitfaq(3tcl)           Snit's Not Incr Tcl, OO system           snitfaq(3tcl)

______________________________________________________________________________

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 fre-
       quently 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 ap-
       plication.

       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 ap-
       plication.

       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  compli-
       cated.   But  Snit  is about implementing a clean interface to manage a
       collection of thousands of nearly identical carefully-specified  light-
       weight  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.wjdu-
       quette.com/snit.

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

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

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

       o      Snit  megawidgets  should  be (to the extent possible) indistin-
              guishable in interface from Tk widgets.

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

       o      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  in-
       heritance  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 ob-
       ject; 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:

       o      Create abstract data types and Tk megawidgets.

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

       o      Define constructors, destructors, instance methods,  type  meth-
              ods, procs.

       o      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 advan-
       tage of a number of new features of Tcl 8.5 to improve  run-time  effi-
       ciency;  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 re-
       quires 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  in-
       stead:

              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 replace-
       ment for Snit  1.3.  Unfortunately,  some  incompatibilities  were  in-
       evitable  because Snit 2.2 uses Tcl 8.5's new namespace ensemble mecha-
       nism 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  imple-
       mentation.

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

       o      Snit 1.3 supports implicit naming of objects.  Suppose  you  de-
              fine  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  en-
              semble mechanism; and namespace ensemble doesn't allow an ensem-
              ble 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 nam-
              ing 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

       o      Hierarchical methods and type methods  are  implemented  differ-
              ently in Snit 2.2.

              A  hierarchical  method  is an instance method which has subcom-
              mands; these subcommands are themselves methods.   The  Tk  text
              widget's tag command and its subcommands are examples of hierar-
              chical methods.  You can implement such subcommands in Snit sim-
              ply 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 subcom-
              mands, 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.

       o      The third incompatibility derives from the second.  In Snit 1.3,
              hierarchical  methods  were  also simply methods whose name con-
              tains 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 ex-
              ample, the list returned by $obj info methods would include  tag
              but not tag configure or tag cget.

       o      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 in-
              cluding 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  com-
              mands  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.

       o      Method dispatch is considerably faster.

       o      Many error messages and stack traces are cleaner.

       o      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 -simpledis-
              patch is no longer needed.

       o      In Snit 2.2, a type's code (methods,  type  methods,  etc.)  can
              call  commands from the type's parent namespace without qualify-
              ing 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 de-
              fined 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  ob-
       ject's  methods are subcommands of the Tcl command.  The object's prop-
       erties 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 -- ob-
       jects -- 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.  Con-
       ventionally, 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:

       o      snit::type

       o      snit::widget

       o      snit::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 VARI-
       ABLES, 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  in-
       stance  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 ref-
       erence 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 re-
       named 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 re-
       named command.

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

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

       o      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.

       o      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 ar-
              guments to the end of the command as usual.

       o      Every object has a private namespace; the name of this namespace
              is  available  in  method  bodies, etc., as the value of the im-
              plicit 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.

       o      When a snit::widget's instance command is renamed, its Tk window
              name  remains the same -- and is still extremely important. Con-
              sequently, 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::widgetadap-
       tor) 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 hierar-
       chy.

       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  ac-
       cess  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  ob-
       ject'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 it-
       self, using the object name stored in the implicit argument self.

       Suppose, for example, that our dogs never chase anything without  bark-
       ing 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 al-
       lows 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 wid-
       get's tag method are hierarchical methods.

   HOW DO I DEFINE A HIERARCHICAL METHOD?
       Define methods whose names consist of multiple words.  These words  de-
       fine 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 im-
       plicit  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 pub-
       lic  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 ob-
       ject'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 con-
       stant 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 name-
       space; 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::wid-
       getadaptor.  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 compo-
       nents together.  But suppose that the dog object has a graphical inter-
       face  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::wid-
       getadaptor 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 over-
       ride a method such that your renamed widget will call  the  widgetadap-
       tor'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 partic-
       ular 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)  be-
       fore 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 op-
       tions, 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 de-
       clared.

       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 in-
       stance 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  up-
       date 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 vari-
       able 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 lan-
       guages 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 OP-
       TION 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" op-
       tions.

   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 exam-
       ple,  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 own-
       ers evidently take care of him, because he's had his shots.

       Note: If the type defines a constructor, it can specify a different ob-
       ject-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 in-
       stance 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 con-
       stant.   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  op-
       tion  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 writ-
       ten 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 meth-
       ods.  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 argu-
       ments, 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 refer-
       ence 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  up-
       date 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 vari-
       able's name in your documentation so that clients  can  access  it  di-
       rectly.  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-quali-
       fied 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:  cre-
       ate, 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 conven-
       tion, 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 im-
       plicitly 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  my-
       typemethod 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  name-
       space.   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 con-
       structor 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-val-
       ued 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  construc-
       tor  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 con-
       structor, 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 argu-
       ments that follow the object's name.  The constructor is allowed to in-
       terpret  this  list any way it chooses; the normal convention is to as-
       sume that it's a list of option names and values, as shown in the exam-
       ple  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 op-
       tions  to  components,  and  there  are  specific  issues  relating  to
       snit::widgets  and snit::widgetadaptors.  See DELEGATION, WIDGETS, WID-
       GET 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 IN-
       STANCE 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 de-
       stroyed automatically, nor are non-widget components of  Snit  megawid-
       gets.   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 destruc-
       tor 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 mislead-
       ing, 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  de-
       clares an instance variable which is used to store the component's com-
       mand 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  my-
       tail 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 re-
       ferred 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 com-
       ponent 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 dele-
       gate methods or options.  Under this definition, our object  will  usu-
       ally  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 compo-
       nent 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 com-
       mand, 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  ac-
       cordingly.   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 qual-
       ified 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 cre-
       ated in the ::dog:: namespace, and will thus have the  name  ::dog::my-
       tail.

       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 com-
       ponents  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 usu-
       ally 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  en-
       capsulation.

       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 -pub-
       lic  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 com-
       ponents and type components is the same as the relationship between IN-
       STANCE 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  in-
       stall 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 COM-
       PONENTS.

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 ob-
       jects  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  cre-
       ates  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 state-
       ment.

       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  sub-
       command of a different object command).  But not all Tcl objects follow
       Tk conventions, and not everything you'd to which you'd like  to  dele-
       gate a method is necessary an object.  Consequently, Snit makes it easy
       to delegate a method to pretty much anything you like using  the  dele-
       gate 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 com-
       mands 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 com-
       mand.

       The using clause understands a number of other %-conversions; in  addi-
       tion  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 dele-
       gate 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 compo-
       nent...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 -cget-
       method  shown  under the first question in this section: whenever a dog
       object's -length option is set or retrieved, the  underlying  tail  ob-
       ject'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 ex-
       ample, 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 be-
       haviors--moving,  eating,  sleeping, and so forth.  We want our dog ob-
       jects 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 compo-
       nent:

              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 op-
       tion names that animal will receive.  It gets anything dog doesn't rec-
       ognize--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 us-
       ing 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 delegat-
       ing  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  sup-
       press?

       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 dele-
       gated options.  Similarly, dogs can neither fly nor climb,  so  we  ex-
       clude 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 every-
       thing 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  state-
       ments, plus a couple of others which will be mentioned below.

   HOW DO SNIT::WIDGETS DIFFER FROM SNIT::TYPES?
       o      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 wid-
              get must already exist.

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

       o      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.

       o      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  piggy-
       backs  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; how-
       ever, 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::la-
       belframe, 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 pret-
       tyframe:

              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  megaw-
       idget.  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::wid-
       get'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::wid-
       getadaptor  looks  just like that for a snit::type or snit::widget, ex-
       cept 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 wid-
       get 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::widgetadap-
       tor,  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  destruc-
       tion--you have to make sure that your megawidget code receives the <De-
       stroy> 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  main-
       tained  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 imple-
       mentation, 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 wid-
       get 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.

       o      If the widget's default widget class is not what is desired, set
              it explicitly using the widgetclass statement in the widget def-
              inition.

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

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

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

       o      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 op-
       tions 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 exam-
       ple, the widget class of the Tk button widget is Button.

       Similarly, the widget class of a snit::widget defaults to the  unquali-
       fied  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 an-
       other  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 val-
       ues 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  in-
       ferred 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  dele-
       gated), 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 let-
       ter.  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-de-
       fined options, using the option's resource and class name.  If the  re-
       sult isn't "", then it replaces the default value given in widget defi-
       nition.  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  implic-
       itly 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 dele-
       gated to the hull; thus, retrieving it is the same as retrieving -hull-
       background.   Note  that  this  case is unusual; the -background option
       should probably have been excluded using the delegate  statement's  ex-
       cept 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 ac-
       cordance with the standard Tk naming for this option.  As with -relief,
       the  hull  picks  up  its own -borderwidth option before Snit does any-
       thing.  Because the option is delegated under its own  name,  Snit  as-
       sumes  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 adap-
       tors retain the widget class of their hull, and the hull is not created
       automatically  by Snit.  Instead, the snit::widgetadaptor must call in-
       stallhull 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 com-
       mand 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 au-
       tomatically.  Non-hull components are somewhat  more  complicated,  be-
       cause 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 cre-
       ate  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 initial-
       ize 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:

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

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

       o      Creates the component using the specified command, after insert-
              ing into it a list of options and values read  from  the  option
              database.   Thus,  the  explicitly included options (like -fore-
              ground) will override anything read from the option database.

       o      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 op-
              tions implicitly delegated to the component which were  not  ex-
              plicitly 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::wid-
       get  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  cre-
       ated  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 com-
       mands 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 ensem-
       ble 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 de-
       stroy  subcommands  you  don't  want.   And worse yet, since the create
       method can be implicit, users of your command will accidentally be cre-
       ating 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  unex-
       pected 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:

       o      Methods cannot be delegated.

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

       o      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 im-
       plement 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 be-
       comes 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,  in-
       cluding 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 out-
       put 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
       Copyright (c) 2003-2006, by William H. Duquette

tcllib                                2.2                        snitfaq(3tcl)

Man(1) output converted with man2html
list of all man pages