snitfaq man page on Ubuntu

Man page or keyword search:  
man Server   6591 pages
apropos Keyword Search (all sections)
Output format
Ubuntu logo
[printable version]

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

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

       Snit isn't about implementing thousands of nearly identical  carefully-
       specified  lightweight  thingamajigs--not  as  individual Snit objects.
       Traditional Tcl methods will be much faster, and not much more  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?
       ·      A Snit object should be at least as efficient  as	 a  hand-coded
	      Tcl object (see http://www.wjduquette.com/tcl/objects.html).

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

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

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

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

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

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

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

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

       ·      Create abstract data types and Tk megawidgets.

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

       ·      Define constructors, destructors, instance methods,  type	 meth‐
	      ods, procs.

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

SNIT VERSIONS
   WHICH VERSION OF SNIT SHOULD I USE?
       The current Snit distribution includes two versions, Snit 1.3 and  Snit
       2.2.   The  reason that both are included is that Snit 2.2 takes 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
       requires only Tcl 8.3 and later.

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

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

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

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

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

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

   HOW ARE SNIT 1.3 AND SNIT 2.2 INCOMPATIBLE?
       To  the	extent possible, Snit 2.2 is intended to be a drop-in replace‐
       ment  for  Snit	1.3.  Unfortunately,   some   incompatibilities	  were
       inevitable because Snit 2.2 uses Tcl 8.5's new namespace ensemble mech‐
       anism 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.

       ·      Snit 1.3 supports	 implicit  naming  of  objects.	  Suppose  you
	      define a new snit::type called dog.  You can create instances of
	      dog in three ways:
	      dog spot		     ;# Explicit naming
	      set obj1 [dog %AUTO%]  ;# Automatic naming
	      set obj2 [dog]	     ;# Implicit naming

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

	      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

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

       ·      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
	      example,	the  list  returned by $obj info methods would include
	      tag but not tag configure or tag cget.

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

	      This  is extremely convenient.  However, it also means that 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.

       ·      Method dispatch is considerably faster.

       ·      Many error messages and stack traces are cleaner.

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

       ·      In  Snit	2.2,  a	 type's code (methods, type methods, etc.) can
	      call commands from the type's parent namespace without  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
	      defined by the package without any extra work.

	      This  feature depends on the new Tcl 8.5 namespace path command,
	      which is why it hasn't been implemented for V1.x.	 V1.x code can
	      achieve something similar by placing
	      namespace import [namespace parent]::*
	      in  a  type  constructor.	  This	is less useful, however, as it
	      picks up only those commands which have already been exported by
	      the parent namespace at the time the type is defined.

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

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

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

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

       Further, an instance is also a Tcl command--a command that gives access
       to the operations which are defined for that abstract data type.	  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:

       ·      snit::type

       ·      snit::widget

       ·      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
       instance name doesn't conflict with any defined TYPE METHODS. (See TYPE
       COMPONENTS  for	the  special case in which this doesn't work.)	So the
       following example is identical to the previous example:

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

       This document generally uses the shorter form.

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

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

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

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

       % spot bark
       ::spot barks.
       %

   HOW DO I REFER TO AN OBJECT INDIRECTLY?
       Some programmers prefer to save the object name in a variable, and 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
       renamed command.

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

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

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

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

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

		  .btn configure -command [list $self ButtonPress]

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

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

		  .btn configure -command [mymethod ButtonPress]

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

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

       ·      When a snit::widget's instance command is renamed, its Tk window
	      name remains the same -- and is still extremely important.  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
       access to all of the object's type variables, instance  variables,  and
       so forth.

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

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

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

       A dog can bark, and it can chase things.

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

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

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

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

       Suppose,	 for example, that our dogs never chase anything without 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
       allows  the  programmer to define a tree-shaped command structure, such
       as is used by many of the Tk widgets--the subcommands of	 the  Tk  text
       widget's tag method are hierarchical methods.

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

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

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

   HOW DO I CALL HIERARCHICAL METHODS?
       As subcommands of subcommands.
       % mytext .text
       .text
       % .text tag configure redtext -foreground red -background black
       % .text tag cget redtext -foreground
       red
       %

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

       Snit doesn't implement any access control on instance methods,  so  all
       methods are de facto public.  Conventionally, though, the names of 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
       object's type:

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

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

       If  the object's command is renamed, then $self will change to match in
       subsequent calls.  Thus, your code should not assume that $self is 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	names‐
       pace;  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)
       before you reference it.

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

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

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

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

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

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

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

       The second method is to declare your instance variables	explicitly  in
       your instance code, while not including them in the type definition:
       snit::type dog {
	   constructor {} {
	       variable mood

	       set mood happy
	   }

	   method setmood {newMood} {
	       variable mood

	       set mood $newMood
	   }

	   method getmood {} {
	       variable mood

	       return $mood
	   }
       }

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

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

       If you naively pass the instance variable name  to  the	label  widget,
       you'll  be confused by the result; Tk will assume that the name names a
       global variable.	 Instead, you need to provide a fully-qualified	 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
       OPTION  DATABASE;  snit::widget and snit::widgetadaptor objects, on the
       other hand, always do.

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

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

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

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

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

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

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

   HOW CAN A CLIENT SET OPTIONS AT OBJECT CREATION?
       The normal convention is that the client may pass any number of options
       and their values after the object's name at object creation.  For 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
       object-creation syntax.	See CONSTRUCTORS for more information.

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

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

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

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

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

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

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

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

       The results are the same.

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

       % snit::type dog {
	   option -weight 10

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

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

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

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

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

       Suppose you've got an option that determines how instances of your type
       are constructed; it must be set at creation time, after which it's 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
       option is given a new value via the configure or configurelist instance
       methods.	 The  method can pass the value on to some other object, store
       it in a database, or do anything else you'd like it to do.

       Here's what the default configuration behavior would look like if 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
       update the label's value just by assigning a new value to the variable.

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

       snit::widget mywidget {
	   typevariable labeltext ""

	   constructor {args} {
	       # ...

	       label $win.label -textvariable [mytypevar labeltext]

	       # ...
	   }
       }

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

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

       snit::type mytype {
	   typevariable myvariable
       }

       set ::mytype::myvariable "New Value"

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

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

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

	   typemethod pedigreedDogs {} {
	       return $pedigreed
	   }
       }

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

       The typemethod statement looks just like a normal Tcl proc, except that
       it  appears  in a snit::type definition.	 Notice that every type method
       gets an implicit argument called type, which contains the  fully-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
       implicitly defined for INSTANCE METHODS.

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

       snit::type dog {

	   typemethod pedigreedDogs {} { ... }

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

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

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

       Alternatively,	from   a  method  or  type  method  you	 can  use  the
       mytypemethod command, just as you would use mymethod to define a	 call‐
       back 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 names‐
       pace.  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
       interpret this list any way it chooses; the  normal  convention	is  to
       assume  that  it's  a  list of option names and values, as shown in the
       example above.  If you simply want  to  save  the  option  values,  you
       should use the configurelist method, as shown.

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

       % snit::type dog {
	   variable breed

	   option -color brown
	   option -akc 0

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

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

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

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

   IS THERE ANYTHING SPECIAL ABOUT WRITING THE CONSTRUCTOR?
       Yes.  Writing the  constructor  can  be	tricky	if  you're  delegating
       options	to  components,	 and  there  are  specific  issues relating to
       snit::widgets and snit::widgetadaptors.	See DELEGATION, WIDGETS,  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
       INSTANCE METHODS: type, selfns, win, and self.

   MUST COMPONENTS BE DESTROYED EXPLICITLY?
       Yes and no.

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

       Components  of  normal  snit::types,  on	 the  other  hand,  are	 never
       destroyed automatically, nor are non-widget components of Snit 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
       declares an instance variable which is used to  store  the  component's
       command name when the component is created.

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

       snit::type dog {
	   component mytail

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

	   method wag {} {
	       $mytail wag
	   }
       }

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

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

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

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

   ARE THERE ANY LIMITATIONS ON COMPONENT NAMES?
       Yes.  snit::widget and snit::widgetadaptor objects have a special  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
       accordingly.  For consistency, it's a good idea to get in the habit  of
       using install for all owned components.

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

   ARE THERE ANY LIMITATIONS ON COMPONENT OBJECT NAMES?
       Yes.

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

       Component objects which are not widgets or megawidgets must have fully-
       qualified command names, i.e., names which include the  full  namespace
       of the command.	Note that Snit always creates objects with fully 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::mytail.

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

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

	   install mytail using tail %AUTO%

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

	   install mytail using tail ${selfns}::mytail

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

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

       If your object is an instance of snit::type, though, none of its	 owned
       components will be destroyed automatically, nor will be non-widget 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
       encapsulation.

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

   HOW DO I EXPOSE A COMPONENT'S OBJECT COMMAND?
       When you declare the component, specify the component statement's -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
       INSTANCE	 VARIABLES and TYPE VARIABLES.	Both INSTANCE METHODS and TYPE
       METHODS can be delegated to type components.

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

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

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

       snit::type dog {
	   typecomponent vet

	   # ...
       }

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

       You'll usually install type components  in  the	type  constructor,  as
       shown here:
       snit::type veterinarian { ... }

       snit::type dog {
	   typecomponent vet

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

   ARE THERE ANY LIMITATIONS ON TYPE COMPONENT NAMES?
       Yes, the same as on INSTANCE VARIABLES, TYPE VARIABLES, and normal 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
       objects can do the same thing.  The following example shows one way  in
       which  the  dog	object can delegate its wag method and its -taillength
       option to its tail component.

       snit::type dog {
	   variable mytail

	   option -taillength -configuremethod SetTailOption -cgetmethod GetTailOption

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

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

	   method wag {} {
	       $mytail wag
	   }

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

       }

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

       Note  that the constructor calls the configurelist method after it 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
       object's option is set or retrieved in turn.

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

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

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

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

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

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

	   option -akc 0

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

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

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

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

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

   HOW CAN I DELEGATE ALL BUT CERTAIN METHODS OR OPTIONS TO A COMPONENT?
       In the previous answer, we said that every dog is an animal by 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
       exclude those animal methods as shown.

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

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

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

	   # ...

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

	   # ...
       }

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

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

	   # ...
       }

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

       A snit::widget is also a special kind of snit::type.  Just about 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?
       ·      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.

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

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

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

   WHAT IS A HULL COMPONENT?
       Snit can't create a Tk widget object; only Tk can do that.  Thus, every
       instance of a snit::widget must be wrapped around a genuine Tk  widget;
       this  Tk	 widget is called the hull component.  Snit effectively 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::labelframe,	 and  ttk::toplevel.   To enable the use of some other
       kind of widget as the hull type, you can lappend the widget command  to
       the  variable  snit::hulltypes  (always provided the widget defines the
       -class option.  For example, suppose Tk gets a new widget type called a
       prettyframe:

       lappend snit::hulltypes prettyframe

       snit::widget mywidget {
	   hulltype prettyframe

	   # ...
       }

   HOW SHOULD I NAME WIDGETS WHICH ARE COMPONENTS OF A SNIT::WIDGET?
       Every  widget, whether a genuine Tk widget or a Snit megawidget, has to
       have a valid Tk window name.  When a snit::widget is first created, its
       instance	 name, self, is a Tk window name; however, if the snit::widget
       is used as the hull component by	 a  snit::widgetadaptor	 its  instance
       name  will  be  changed	to  something  else.   For  this reason, every
       snit::widget method, constructor, destructor, and so  forth  is	passed
       another	implicit argument, win, which is the window name of the 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,
       except that the constructor must create and install the hull component.

       For  example, the following code creates a read-only text widget by the
       simple device of turning its insert and	delete	methods	 into  no-ops.
       Then,  we  define  new methods, ins and del, which get delegated to the
       hull component as insert and delete.  Thus, we've adapted the text 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
       <Destroy> event before the megawidget you're adapting does.

THE TK OPTION DATABASE
   WHAT IS THE TK OPTION DATABASE?
       The  Tk	option	database  is a database of default option values 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.

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

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

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

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

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

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

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

       If  you	create	an  instance  of  a  snit::type	 as  a	component of a
       snit::widget or snit::widgetadaptor, on the  other  hand,  and  if  any
       options	are delegated to the component, and if you use install to cre‐
       ate 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
       another widget's behavior.  Then, it will usually  not  make  sense  to
       change the widget's widget class anyway.

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

       The resource and class names are used to initialize option default 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
       inferred from the option name, but not always.

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

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

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

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

       For  all	 other	options	 (whether  locally defined or explicitly 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-
       defined	options,  using	 the option's resource and class name.	If the
       result isn't "", then it replaces the default  value  given  in	widget
       definition.  In either case, the default can be overridden by the call‐
       er.  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
       except clause, or (more likely) delegated to some other component.

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

	   delegate option {-borderwidth borderWidth BorderWidth} to hull

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

       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
       automatically.  Non-hull	 components  are  somewhat  more  complicated,
       because they are matched against the option database twice.

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

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

       Before option database support was added to Snit, the usual way to 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:

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

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

       ·      Creates the component using the specified command, after 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.

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

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

   WHAT HAPPENS IF I INSTALL A NON-WIDGET AS A COMPONENT OF WIDGET?
       A snit::type never queries the option database.	However, a  snit::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
       destroy	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:

       ·      Methods cannot be delegated.

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

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

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

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

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

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

       It's  easily done.  Outside of any type definition, define a macro that
       returns 1 if the extension is available, and 0 otherwise:
       if {$gotFastExtension} {
	   snit::macro fastcode {} {return 1}
       } else {
	   snit::macro fastcode {} {return 0}
       }

       Then, use your macro in your type definition:
       snit::type dog {

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

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

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

       For one option, this is fine; if you've got a  number  of  options,  it
       becomes tedious and error prone.	 So package it as a macro:
       snit::macro propagate {option "to" components} {
	   option $option -configuremethod Propagate$option

	   set body "\n"

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

	   method Propagate$option {option value} $body
       }

       Then you can use it like this:
       snit::widget mywidget {
	   option -background default -white
	   option -foreground default -black

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

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

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

       If my fancy snit::widget is called ::mylib::mywidget, for example, then
       I should define my propagate macro as ::mylib::propagate:
       snit::macro mylib::propagate {option "to" components} { ... }

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

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

BUGS, IDEAS, FEEDBACK
       This document, and the package it describes, will  undoubtedly  contain
       bugs  and  other	 problems.  Please report such in the category snit of
       the	   Tcllib	  SF	     Trackers	       [http://source‐
       forge.net/tracker/?group_id=12883].   Please  also report any ideas for
       enhancements you may have for either package and/or documentation.

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

snit				      2.2			 snitfaq(3tcl)
[top]

List of man pages available for Ubuntu

Copyright (c) for man pages and the logo by the respective OS vendor.

For those who want to learn more, the polarhome community provides shell access and support.

[legal] [privacy] [GNU] [policy] [cookies] [netiquette] [sponsors] [FAQ]
Tweet
Polarhome, production since 1999.
Member of Polarhome portal.
Based on Fawad Halim's script.
....................................................................
Vote for polarhome
Free Shell Accounts :: the biggest list on the net