1snitfaq(n)              Snit's Not Incr Tcl, OO system              snitfaq(n)
2
3
4
5______________________________________________________________________________
6

NAME

8       snitfaq - Snit Frequently Asked Questions
9

DESCRIPTION

OVERVIEW

12   WHAT IS THIS DOCUMENT?
13       This  is  an  atypical  FAQ list, in that few of the questions are fre‐
14       quently asked.  Rather, these are the questions I think a  newcomer  to
15       Snit  should be asking.  This file is not a complete reference to Snit,
16       however; that information is in the snit man page.
17
18   WHAT IS SNIT?
19       Snit is a framework for defining abstract data types and megawidgets in
20       pure Tcl.  The name "Snit" stands for "Snit's Not Incr Tcl", signifying
21       that Snit takes a different approach to defining objects than does Incr
22       Tcl, the best known object framework for Tcl.  Had I realized that Snit
23       would become at all popular, I'd probably have chosen something else.
24
25       The primary purpose of Snit is to be object glue--to help  you  compose
26       diverse  objects  from  diverse sources into types and megawidgets with
27       clean, convenient interfaces so that you can  more  easily  build  your
28       application.
29
30       Snit  isn't  about  theoretical purity or minimalist design; it's about
31       being able to do powerful things easily and consistently without having
32       to  think  about  them--so  that  you  can concentrate on building your
33       application.
34
35       Snit isn't about implementing thousands of nearly identical  carefully-
36       specified  lightweight  thingamajigs--not  as  individual Snit objects.
37       Traditional Tcl methods will be much faster, and not much more  compli‐
38       cated.   But  Snit  is about implementing a clean interface to manage a
39       collection of thousands of nearly identical carefully-specified  light‐
40       weight  thingamajigs  (e.g., think of the text widget and text tags, or
41       the canvas widget and canvas objects).  Snit lets you hide the  details
42       of  just  how those thingamajigs are stored--so that you can ignore it,
43       and concentrate on building your application.
44
45       Snit isn't a way of life, a silver bullet, or the  Fountain  of  Youth.
46       It's  just  a  way  of managing complexity--and of managing some of the
47       complexity of managing  complexity--so  that  you  can  concentrate  on
48       building your application.
49
50   WHAT VERSION OF TCL DOES SNIT REQUIRE?
51       Snit 1.3 requires Tcl 8.3 or later; Snit 2.2 requires Tcl 8.5 or later.
52       See SNIT VERSIONS for the differences between Snit 1.3 and Snit 2.2.
53
54   WHERE CAN I DOWNLOAD SNIT?
55       Snit is part of Tcllib, the standard Tcl library, so you might  already
56       have  it.   It's also available at the Snit Home Page, http://www.wjdu
57       quette.com/snit.
58
59   WHAT ARE SNIT'S GOALS?
60       ·      A Snit object should be at least as efficient  as  a  hand-coded
61              Tcl object (see http://www.wjduquette.com/tcl/objects.html).
62
63       ·      The fact that Snit was used in an object's implementation should
64              be transparent (and irrelevant) to clients of that object.
65
66       ·      Snit should be able to encapsulate objects from  other  sources,
67              particularly Tk widgets.
68
69       ·      Snit  megawidgets  should  be (to the extent possible) indistin‐
70              guishable in interface from Tk widgets.
71
72       ·      Snit should be Tclish--that is, rather than  trying  to  emulate
73              C++,  Smalltalk,  or anything else, it should try to emulate Tcl
74              itself.
75
76       ·      It should have a simple, easy-to-use, easy-to-remember syntax.
77
78   HOW IS SNIT DIFFERENT FROM OTHER OO FRAMEWORKS?
79       Snit is unique among Tcl object systems in that  it  is  based  not  on
80       inheritance  but  on  delegation.   Object systems based on inheritance
81       only allow you to inherit from classes defined using the  same  system,
82       and  that's  a  shame.  In Tcl, an object is anything that acts like an
83       object; it shouldn't matter how the object was implemented.  I designed
84       Snit  to help me build applications out of the materials at hand; thus,
85       Snit is designed to be able to incorporate and  build  on  any  object,
86       whether  it's  a  hand-coded object, a Tk widget, an Incr Tcl object, a
87       BWidget or almost anything else.
88
89       Note that you can achieve the effect of  inheritance  using  COMPONENTS
90       and DELEGATION--and you can inherit from anything that looks like a Tcl
91       object.
92
93   WHAT CAN I DO WITH SNIT?
94       Using Snit, a programmer can:
95
96       ·      Create abstract data types and Tk megawidgets.
97
98       ·      Define instance variables, type variables, and Tk-style options.
99
100       ·      Define constructors, destructors, instance methods,  type  meth‐
101              ods, procs.
102
103       ·      Assemble  a  type  out of component types.  Instance methods and
104              options can be delegated to the component types automatically.
105

SNIT VERSIONS

107   WHICH VERSION OF SNIT SHOULD I USE?
108       The current Snit distribution includes two versions, Snit 1.3 and  Snit
109       2.2.   The  reason that both are included is that Snit 2.2 takes advan‐
110       tage of a number of new features of Tcl 8.5 to improve  run-time  effi‐
111       ciency;  as  a  side-effect,  the ugliness of Snit's error messages and
112       stack traces has been reduced considerably.  The  cost  of  using  Snit
113       2.2, of course, is that you must target Tcl 8.5.
114
115       Snit  1.3,  on  the  other  hand,  lacks  Snit 2.2's optimizations, but
116       requires only Tcl 8.3 and later.
117
118       In short, if you're targetting Tcl 8.3 or 8.4 you should use Snit  1.3.
119       If  you  can  afford  to target Tcl 8.5, you should definitely use Snit
120       2.2.  If you will be targetting both, you can use Snit 1.3 exclusively,
121       or  (if  your code is unaffected by the minor incompatibilities between
122       the two versions) you can use Snit 1.3 for Tcl 8.4 and Snit 2.2 for Tcl
123       8.5.
124
125   HOW DO I SELECT THE VERSION OF SNIT I WANT TO USE?
126       To always use Snit 1.3 (or a later version of Snit 1.x), invoke Snit as
127       follows:
128
129              package require snit 1.3
130
131       To always use Snit 2.2 (or a later  version  of  Snit  2.x),  say  this
132       instead:
133
134              package require snit 2.2
135
136       Note  that  if  you  request Snit 2.2 explicitly, your application will
137       halt with Tcl 8.4, since Snit 2.2 is unavailable for Tcl 8.4.
138
139       If you wish your application to always use the latest available version
140       of Snit, don't specify a version number:
141
142              package require snit
143
144       Tcl  will find and load the latest version that's available relative to
145       the version of Tcl being used.  In this case, be careful to avoid using
146       any incompatible features.
147
148   HOW ARE SNIT 1.3 AND SNIT 2.2 INCOMPATIBLE?
149       To  the  extent possible, Snit 2.2 is intended to be a drop-in replace‐
150       ment  for  Snit  1.3.  Unfortunately,   some   incompatibilities   were
151       inevitable because Snit 2.2 uses Tcl 8.5's new namespace ensemble mech‐
152       anism to implement subcommand dispatch.  This approach is  much  faster
153       than  the  mechanism  used in Snit 1.3, and also results in much better
154       error messages; however, it also places new constraints on  the  imple‐
155       mentation.
156
157       There  are  four  specific  incompatibilities between Snit 1.3 and Snit
158       2.2.
159
160       ·      Snit 1.3 supports  implicit  naming  of  objects.   Suppose  you
161              define a new snit::type called dog.  You can create instances of
162              dog in three ways:
163
164              dog spot               ;# Explicit naming
165              set obj1 [dog %AUTO%]  ;# Automatic naming
166              set obj2 [dog]         ;# Implicit naming
167
168
169              In Snit 2.2, type  commands  are  defined  using  the  namespace
170              ensemble  mechanism;  and  namespace  ensemble  doesn't allow an
171              ensemble command to be called without a subcommand.   In  short,
172              using namespace ensemble there's no way to support implicit nam‐
173              ing.
174
175              All is not lost, however.  If the type has no type methods, then
176              the  type  command  is a simple command rather than an ensemble,
177              and namespace ensemble is not used.  In this case, implicit nam‐
178              ing is still possible.
179
180              In  short,  you can have implicit naming if you're willing to do
181              without type methods (including the standard type methods,  like
182              $type info).  To do so, use the -hastypemethods pragma:
183
184              pragma -hastypemethods 0
185
186       ·      Hierarchical  methods  and  type methods are implemented differ‐
187              ently in Snit 2.2.
188
189              A hierarchical method is an instance method  which  has  subcom‐
190              mands;  these  subcommands  are themselves methods.  The Tk text
191              widget's tag command and its subcommands are examples of hierar‐
192              chical methods.  You can implement such subcommands in Snit sim‐
193              ply by including multiple words in the method names:
194
195              method {tag configure} {tag args} { ... }
196
197              method {tag cget} {tag option} {...}
198
199
200              Here we've implicitly defined a tag method which has two subcom‐
201              mands, configure and cget.
202
203              In Snit 1.3, hierarchical methods could be called in two ways:
204
205              $obj tag cget -myoption      ;# The good way
206              $obj {tag cget} -myoption    ;# The weird way
207
208
209              In  the  second  call, we see that a hierarchical method or type
210              method is simply one whose name contains multiple words.
211
212              In Snit 2.2 this is no longer the case, and the "weird"  way  of
213              calling hierarchical methods and type methods no longer works.
214
215       ·      The third incompatibility derives from the second.  In Snit 1.3,
216              hierarchical methods were also simply methods  whose  name  con‐
217              tains  multiple  words.  As a result, $obj info methods returned
218              the full names of all  hierarchical  methods.   In  the  example
219              above,  the list returned by $obj info methods would include tag
220              configure and tag cget but not tag, since tag  is  defined  only
221              implicitly.
222
223              In Snit 2.2, hierarchical methods and type methods are no longer
224              simply ones whose name contains multiple  words;  in  the  above
225              example,  the  list  returned by $obj info methods would include
226              tag but not tag configure or tag cget.
227
228       ·      The fourth incompatibility is due to a new  feature.   Snit  2.2
229              uses  the  new  namespace path command so that a type's code can
230              call any command defined in the type's parent namespace  without
231              qualification  or  importation.  For example, suppose you have a
232              package called mypackage which  defines  a  number  of  commands
233              including  a  type,  ::mypackage::mytype.   Thanks  to namespace
234              path, the type's code can call any of the other commands defined
235              in ::mypackage::.
236
237              This  is extremely convenient.  However, it also means that com‐
238              mands defined in the parent namespace, ::mypackage::  can  block
239              the  type's  access  to identically named commands in the global
240              namespace.  This can lead to bugs.  For example, Tcllib includes
241              a  type  called  ::tie::std::file.   This  type's code calls the
242              standard file command.  When run with Snit 2.2, the code broke--
243              the type's command, ::tie::std::file, is itself a command in the
244              type's parent namespace, and so instead of calling the  standard
245              file command, the type found itself calling itself.
246
247   ARE THERE OTHER DIFFERENCES BETWEEN SNIT 1.X AND SNIT 2.2?
248       Yes.
249
250       ·      Method dispatch is considerably faster.
251
252       ·      Many error messages and stack traces are cleaner.
253
254       ·      The  -simpledispatch pragma is obsolete, and ignored if present.
255              In Snit 1.x, -simpledispatch substitutes a faster mechanism  for
256              method  dispatch,  at the cost of losing certain features.  Snit
257              2.2 method dispatch is faster still in all cases, so -simpledis‐
258              patch is no longer needed.
259
260       ·      In  Snit  2.2,  a  type's code (methods, type methods, etc.) can
261              call commands from the type's parent namespace without  qualify‐
262              ing  or importing them, i.e., type ::parentns::mytype's code can
263              call ::parentns::someproc as just someproc.
264
265              This is extremely useful when a type is defined  as  part  of  a
266              larger  package,  and shares a parent namespace with the rest of
267              the package; it means that the  type  can  call  other  commands
268              defined by the package without any extra work.
269
270              This  feature depends on the new Tcl 8.5 namespace path command,
271              which is why it hasn't been implemented for V1.x.  V1.x code can
272              achieve something similar by placing
273
274              namespace import [namespace parent]::*
275
276              in  a  type  constructor.   This  is less useful, however, as it
277              picks up only those commands which have already been exported by
278              the parent namespace at the time the type is defined.
279

OBJECTS

281   WHAT IS AN OBJECT?
282       A  full  description of object-oriented programming is beyond the scope
283       of this FAQ, obviously.  In simple terms, an object is an  instance  of
284       an  abstract  data type--a coherent bundle of code and data.  There are
285       many ways to represent objects in Tcl/Tk; the best known  examples  are
286       the Tk widgets.
287
288       A  Tk  widget  is  an  object; it is represented by a Tcl command.  The
289       object's methods are subcommands of  the  Tcl  command.   The  object's
290       properties  are  options accessed using the configure and cget methods.
291       Snit uses the same conventions as Tk widgets do.
292
293   WHAT IS AN ABSTRACT DATA TYPE?
294       In computer science terms, an abstract data  type  is  a  complex  data
295       structure  along  with  a set of operations--a stack, a queue, a binary
296       tree, etc--that is to say, in modern terms, an object.  In systems that
297       include some form of inheritance the word class is usually used instead
298       of abstract data type, but as Snit  doesn't  implement  inheritance  as
299       it's  ordinarily  understood  the  older  term  seems more appropriate.
300       Sometimes this is called object-based programming as opposed to object-
301       oriented  programming.   Note  that you can easily create the effect of
302       inheritance using COMPONENTS and DELEGATION.
303
304       In Snit, as in Tk, a type  is  a  command  that  creates  instances  --
305       objects  -- which belong to the type.  Most types define some number of
306       options which can be set at creation time, and usually can  be  changed
307       later.
308
309       Further, an instance is also a Tcl command--a command that gives access
310       to the operations which are defined for that abstract data type.   Con‐
311       ventionally,  the operations are defined as subcommands of the instance
312       command.  For example, to insert text into a Tk text  widget,  you  use
313       the text widget's insert subcommand:
314
315                  # Create a text widget and insert some text in it.
316                  text .mytext -width 80 -height 24
317                  .mytext insert end "Howdy!"
318
319
320       In  this  example, text is the type command and .mytext is the instance
321       command.
322
323       In Snit, object subcommands are generally called INSTANCE METHODS.
324
325   WHAT KINDS OF ABSTRACT DATA TYPES DOES SNIT PROVIDE?
326       Snit allows you to define three kinds of abstract data type:
327
328       ·      snit::type
329
330       ·      snit::widget
331
332       ·      snit::widgetadaptor
333
334   WHAT IS A SNIT::TYPE?
335       A snit::type is a non-GUI abstract data type, e.g., a stack or a queue.
336       snit::types  are defined using the snit::type command.  For example, if
337       you were designing a kennel management system for a dog breeder,  you'd
338       need a dog type.
339
340              % snit::type dog {
341                  # ...
342              }
343              ::dog
344              %
345
346
347       This definition defines a new command (::dog, in this case) that can be
348       used to define dog objects.
349
350       An instance of a snit::type can have INSTANCE METHODS,  INSTANCE  VARI‐
351       ABLES, OPTIONS, and COMPONENTS.  The type itself can have TYPE METHODS,
352       TYPE VARIABLES, TYPE COMPONENTS, and PROCS.
353
354   WHAT IS A SNIT::WIDGET?, THE SHORT STORY
355       A snit::widget is a Tk megawidget built using Snit; it is very  similar
356       to a snit::type.  See WIDGETS.
357
358   WHAT IS A SNIT::WIDGETADAPTOR?, THE SHORT STORY
359       A  snit::widgetadaptor uses Snit to wrap an existing widget type (e.g.,
360       a Tk label), modifying its interface to a lesser or greater extent.  It
361       is very similar to a snit::widget.  See WIDGET ADAPTORS.
362
363   HOW DO I CREATE AN INSTANCE OF A SNIT::TYPE?
364       You  create  an  instance of a snit::type by passing the new instance's
365       name to the type's create method.  In the following example, we  create
366       a dog object called spot.
367
368              % snit::type dog {
369                  # ....
370              }
371              ::dog
372              % dog create spot
373              ::spot
374              %
375
376
377       In  general,  the  create  method  name  can  be omitted so long as the
378       instance name doesn't conflict with any defined TYPE METHODS. (See TYPE
379       COMPONENTS  for  the  special case in which this doesn't work.)  So the
380       following example is identical to the previous example:
381
382              % snit::type dog {
383                  # ....
384              }
385              ::dog
386              % dog spot
387              ::spot
388              %
389
390
391       This document generally uses the shorter form.
392
393       If the dog type defines OPTIONS, these can usually be given defaults at
394       creation time:
395
396              % snit::type dog {
397                  option -breed mongrel
398                  option -color brown
399
400                  method bark {} { return "$self barks." }
401              }
402              ::dog
403              % dog create spot -breed dalmation -color spotted
404              ::spot
405              % spot cget -breed
406              dalmation
407              % spot cget -color
408              spotted
409              %
410
411
412       Once  created,  the  instance  name now names a new Tcl command that is
413       used to manipulate the object.  For example, the following  code  makes
414       the dog bark:
415
416              % spot bark
417              ::spot barks.
418              %
419
420
421   HOW DO I REFER TO AN OBJECT INDIRECTLY?
422       Some programmers prefer to save the object name in a variable, and ref‐
423       erence it that way.  For example,
424
425              % snit::type dog { ... }
426              ::dog
427              % set d [dog spot -breed dalmation -color spotted]
428              ::spot
429              % $d cget -breed
430              dalmation
431              % $d bark
432              ::spot barks.
433              %
434
435
436       If you prefer this style, you might prefer to have  Snit  generate  the
437       instance's name automatically.
438
439   HOW CAN I GENERATE THE OBJECT NAME AUTOMATICALLY?
440       If  you'd  like Snit to generate an object name for you, use the %AUTO%
441       keyword as the requested name:
442
443              % snit::type dog { ... }
444              ::dog
445              % set d [dog %AUTO%]
446              ::dog2
447              % $d bark
448              ::dog2 barks.
449              %
450
451
452       The %AUTO% keyword can be embedded in a longer string:
453
454              % set d [dog obj_%AUTO%]
455              ::obj_dog4
456              % $d bark
457              ::obj_dog4 barks.
458              %
459
460
461   CAN TYPES BE RENAMED?
462       Tcl's rename command renames other commands.  It's a  common  technique
463       in  Tcl to modify an existing command by renaming it and defining a new
464       command with the original name;  the  new  command  usually  calls  the
465       renamed command.
466
467       snit::type  commands, however, should never be renamed; to do so breaks
468       the connection between the type and its objects.
469
470   CAN OBJECTS BE RENAMED?
471       Tcl's rename command renames other commands.  It's a  common  technique
472       in  Tcl to modify an existing command by renaming it and defining a new
473       command with the original name;  the  new  command  usually  calls  the
474       renamed command.
475
476       All Snit objects (including widgets and widgetadaptors) can be renamed,
477       though this flexibility has some consequences:
478
479       ·      In an instance method, the implicit argument  self  will  always
480              contain  the  object's  current  name,  so  instance methods can
481              always call other instance methods using $self.
482
483       ·      If the object is  renamed,  however,  then  $self's  value  will
484              change.  Therefore, don't use $self for anything that will break
485              if $self changes. For example, don't pass a callback command  to
486              another object like this:
487
488
489                  .btn configure -command [list $self ButtonPress]
490
491
492              You'll get an error if .btn calls your command after your object
493              is renamed.
494
495       ·      Instead, your object should define  its  callback  command  like
496              this:
497
498
499                  .btn configure -command [mymethod ButtonPress]
500
501
502              The  mymethod  command  returns  code that will call the desired
503              method safely; the caller of the  callback  can  add  additional
504              arguments to the end of the command as usual.
505
506       ·      Every object has a private namespace; the name of this namespace
507              is available in  method  bodies,  etc.,  as  the  value  of  the
508              implicit  argument  selfns.  This value is constant for the life
509              of the object.  Use $selfns instead  of  $self  if  you  need  a
510              unique token to identify the object.
511
512       ·      When a snit::widget's instance command is renamed, its Tk window
513              name remains the same -- and is still extremely important.  Con‐
514              sequently,  the  Tk window name is available in method bodies as
515              the value of the implicit argument win.  This value is  constant
516              for  the  life of the object.  When creating child windows, it's
517              best to use $win.child rather than $self.child as  the  name  of
518              the child window.
519
520   HOW DO I DESTROY A SNIT OBJECT?
521       Any  Snit  object  of  any  type can be destroyed by renaming it to the
522       empty string using the Tcl rename command.
523
524       Snit megawidgets (i.e., instances of snit::widget and snit::widgetadap‐
525       tor)  can  be  destroyed like any other widget: by using the Tk destroy
526       command on the widget or on one of its ancestors in the window  hierar‐
527       chy.
528
529       Every instance of a snit::type has a destroy method:
530
531              % snit::type dog { ... }
532              ::dog
533              % dog spot
534              ::spot
535              % spot bark
536              ::spot barks.
537              % spot destroy
538              % spot barks
539              invalid command name "spot"
540              %
541
542
543       Finally,  every  Snit type has a type method called destroy; calling it
544       destroys the type and all of its instances:
545
546              % snit::type dog { ... }
547              ::dog
548              % dog spot
549              ::spot
550              % spot bark
551              ::spot barks.
552              % dog destroy
553              % spot bark
554              invalid command name "spot"
555              % dog fido
556              invalid command name "dog"
557              %
558
559

INSTANCE METHODS

561   WHAT IS AN INSTANCE METHOD?
562       An instance method is a procedure associated with a specific object and
563       called  as  a  subcommand  of  the  object's command.  It is given free
564       access to all of the object's type variables, instance  variables,  and
565       so forth.
566
567   HOW DO I DEFINE AN INSTANCE METHOD?
568       Instance  methods  are  defined in the type definition using the method
569       statement.  Consider the following code that might be used to add  dogs
570       to a computer simulation:
571
572              % snit::type dog {
573                  method bark {} {
574                      return "$self barks."
575                  }
576
577                  method chase {thing} {
578                      return "$self chases $thing."
579                  }
580              }
581              ::dog
582              %
583
584
585       A dog can bark, and it can chase things.
586
587       The  method statement looks just like a normal Tcl proc, except that it
588       appears in a snit::type definition.  Notice that every instance  method
589       gets  an  implicit  argument  called  self;  this argument contains the
590       object's name.  (There's more on implicit method arguments below.)
591
592   HOW DOES A CLIENT CALL AN INSTANCE METHOD?
593       The method name becomes a subcommand of the object.  For example, let's
594       put a simulated dog through its paces:
595
596              % dog spot
597              ::spot
598              % spot bark
599              ::spot barks.
600              % spot chase cat
601              ::spot chases cat.
602              %
603
604
605   HOW DOES AN INSTANCE METHOD CALL ANOTHER INSTANCE METHOD?
606       If  method A needs to call method B on the same object, it does so just
607       as a client does: it calls method B  as  a  subcommand  of  the  object
608       itself, using the object name stored in the implicit argument self.
609
610       Suppose,  for example, that our dogs never chase anything without bark‐
611       ing at them:
612
613              % snit::type dog {
614                  method bark {} {
615                      return "$self barks."
616                  }
617
618                  method chase {thing} {
619                      return "$self chases $thing.  [$self bark]"
620                  }
621              }
622              ::dog
623              % dog spot
624              ::spot
625              % spot bark
626              ::spot barks.
627              % spot chase cat
628              ::spot chases cat.  ::spot barks.
629              %
630
631
632   ARE THERE ANY LIMITATIONS ON INSTANCE METHOD NAMES?
633       Not really, so long as you avoid the standard  instance  method  names:
634       configure,  configurelist, cget, destroy, and info.  Also, method names
635       consisting of multiple words define hierarchical methods.
636
637   WHAT IS A HIERARCHICAL METHOD?
638       An object's methods are subcommands of the object's  instance  command.
639       Hierarchical  methods  allow an object's methods to have subcommands of
640       their own; and these can in turn have subcommands,  and  so  on.   This
641       allows  the  programmer to define a tree-shaped command structure, such
642       as is used by many of the Tk widgets--the subcommands of  the  Tk  text
643       widget's tag method are hierarchical methods.
644
645   HOW DO I DEFINE A HIERARCHICAL METHOD?
646       Define  methods  whose  names  consist  of multiple words.  These words
647       define the hierarchy  implicitly.   For  example,  the  following  code
648       defines a tag method with subcommands cget and configure:
649
650              snit::widget mytext {
651                  method {tag configure} {tag args} { ... }
652
653                  method {tag cget} {tag option} {...}
654              }
655
656       Note  that  there  is  no explicit definition for the tag method; it is
657       implicit in the definition of tag configure and tag cget.  If you tried
658       to define tag explicitly in this example, you'd get an error.
659
660   HOW DO I CALL HIERARCHICAL METHODS?
661       As subcommands of subcommands.
662
663              % mytext .text
664              .text
665              % .text tag configure redtext -foreground red -background black
666              % .text tag cget redtext -foreground
667              red
668              %
669
670
671   HOW DO I MAKE AN INSTANCE METHOD PRIVATE?
672       It's  often useful to define private methods, that is, instance methods
673       intended to be called only by other methods of the same object.
674
675       Snit doesn't implement any access control on instance methods,  so  all
676       methods are de facto public.  Conventionally, though, the names of pub‐
677       lic methods begin with a lower-case letter, and the  names  of  private
678       methods begin with an upper-case letter.
679
680       For  example, suppose our simulated dogs only bark in response to other
681       stimuli; they never bark just for fun.  So the bark method becomes Bark
682       to indicate that it is private:
683
684              % snit::type dog {
685                  # Private by convention: begins with uppercase letter.
686                  method Bark {} {
687                      return "$self barks."
688                  }
689
690                  method chase {thing} {
691                      return "$self chases $thing. [$self Bark]"
692                  }
693              }
694              ::dog
695              % dog fido
696              ::fido
697              % fido chase cat
698              ::fido chases cat. ::fido barks.
699              %
700
701
702   ARE THERE ANY LIMITATIONS ON INSTANCE METHOD ARGUMENTS?
703       Method  argument  lists  are defined just like normal Tcl proc argument
704       lists; in particular, they can include arguments  with  default  values
705       and the args argument.
706
707       However,  every method also has a number of implicit arguments provided
708       by Snit in addition to those explicitly defined.  The  names  of  these
709       implicit arguments may not used to name explicit arguments.
710
711   WHAT IMPLICIT ARGUMENTS ARE PASSED TO EACH INSTANCE METHOD?
712       The  arguments implicitly passed to every method are type, selfns, win,
713       and self.
714
715   WHAT IS $TYPE?
716       The implicit argument type contains the fully  qualified  name  of  the
717       object's type:
718
719              % snit::type thing {
720                  method mytype {} {
721                      return $type
722                  }
723              }
724              ::thing
725              % thing something
726              ::something
727              % something mytype
728              ::thing
729              %
730
731
732   WHAT IS $SELF?
733       The implicit argument self contains the object's fully qualified name.
734
735       If  the object's command is renamed, then $self will change to match in
736       subsequent calls.  Thus, your code should not assume that $self is con‐
737       stant unless you know for sure that the object will never be renamed.
738
739              % snit::type thing {
740                  method myself {} {
741                      return $self
742                  }
743              }
744              ::thing
745              % thing mutt
746              ::mutt
747              % mutt myself
748              ::mutt
749              % rename mutt jeff
750              % jeff myself
751              ::jeff
752              %
753
754
755   WHAT IS $SELFNS?
756       Each Snit object has a private namespace in which to store its INSTANCE
757       VARIABLES and OPTIONS.  The implicit argument selfns contains the  name
758       of  this  namespace;  its  value never changes, and is constant for the
759       life of the object, even if the object's name changes:
760
761              % snit::type thing {
762                  method myNameSpace {} {
763                      return $selfns
764                  }
765              }
766              ::thing
767              % thing jeff
768              ::jeff
769              % jeff myNameSpace
770              ::thing::Snit_inst3
771              % rename jeff mutt
772              % mutt myNameSpace
773              ::thing::Snit_inst3
774              %
775
776
777       The above example reveals how Snit names an instance's  private  names‐
778       pace;  however,  you should not write code that depends on the specific
779       naming convention, as it might change in future releases.
780
781   WHAT IS $WIN?
782       The implicit argument win is defined for all Snit  methods,  though  it
783       really makes sense only for those of WIDGETS and WIDGET ADAPTORS.  $win
784       is simply the original name of the object, whether it's been renamed or
785       not.   For widgets and widgetadaptors, it is also therefore the name of
786       a Tk window.
787
788       When a snit::widgetadaptor is used to modify the interface of a  widget
789       or megawidget, it must rename the widget's original command and replace
790       it with its own.
791
792       Thus, using win whenever the Tk window name is called for means that  a
793       snit::widget  or  snit::widgetadaptor  can  be  adapted by a snit::wid‐
794       getadaptor.  See WIDGETS for more information.
795
796   HOW DO I PASS AN INSTANCE METHOD AS A CALLBACK?
797       It depends on the context.
798
799       Suppose in my application I have a dog object named fido,  and  I  want
800       fido to bark when a Tk button called .bark is pressed.  In this case, I
801       create the callback command in the usual way, using list:
802
803                  button .bark -text "Bark!" -command [list fido bark]
804
805
806       In typical Tcl style, we use a callback to hook two independent  compo‐
807       nents together.  But suppose that the dog object has a graphical inter‐
808       face and owns the button itself?  In this case, the dog must  pass  one
809       of  its  own instance methods to the button it owns.  The obvious thing
810       to do is this:
811
812              % snit::widget dog {
813                  constructor {args} {
814                      #...
815                      button $win.barkbtn -text "Bark!" -command [list $self bark]
816                      #...
817                  }
818              }
819              ::dog
820              %
821
822
823       (Note that in this example, our dog becomes a snit::widget, because  it
824       has  GUI  behavior.   See  WIDGETS for more.)  Thus, if we create a dog
825       called .spot, it will create a Tk  button  called  .spot.barkbtn;  when
826       pressed, the button will call $self bark.
827
828       Now,  this will work--provided that .spot is never renamed to something
829       else.  But surely renaming widgets is abnormal?  And so  it  is--unless
830       .spot  is  the hull component of a snit::widgetadaptor.  If it is, then
831       it will be renamed, and .spot will become the name  of  the  snit::wid‐
832       getadaptor  object.  When the button is pressed, the command $self bark
833       will be handled by the snit::widgetadaptor, which might or might not do
834       the right thing.
835
836       There's a safer way to do it, and it looks like this:
837
838              % snit::widget dog {
839                  constructor {args} {
840                      #...
841                      button $win.barkbtn -text "Bark!" -command [mymethod bark]
842                      #...
843                  }
844              }
845              ::dog
846              %
847
848
849       The  command  mymethod  takes  any number of arguments, and can be used
850       like list to build up a callback command; the only difference  is  that
851       mymethod  returns  a  form of the command that won't change even if the
852       instance's name changes.
853
854       On the other hand, you might prefer to allow a widgetadaptor  to  over‐
855       ride  a  method such that your renamed widget will call the widgetadap‐
856       tor's method instead of its own.  In this case, using [list $self bark]
857       will  do  what  you want...but this is a technique which should be used
858       only in carefully controlled circumstances.
859
860   HOW DO I DELEGATE INSTANCE METHODS TO A COMPONENT?
861       See DELEGATION.
862

INSTANCE VARIABLES

864   WHAT IS AN INSTANCE VARIABLE?
865       An instance variable is a private variable associated with some partic‐
866       ular Snit object.  Instance variables can be scalars or arrays.
867
868   HOW IS A SCALAR INSTANCE VARIABLE DEFINED?
869       Scalar  instance variables are defined in the type definition using the
870       variable statement.  You can simply name it, or you can  initialize  it
871       with a value:
872
873              snit::type mytype {
874                  # Define variable "greeting" and initialize it with "Howdy!"
875                  variable greeting "Howdy!"
876              }
877
878
879   HOW IS AN ARRAY INSTANCE VARIABLE DEFINED?
880       Array  instance variables are also defined in the type definition using
881       the variable command.  You can initialize them  at  the  same  time  by
882       specifying the -array option:
883
884              snit::type mytype {
885                  # Define array variable "greetings"
886                  variable greetings -array {
887                      formal "Good Evening"
888                      casual "Howdy!"
889                  }
890              }
891
892
893   WHAT HAPPENS IF I DON'T INITIALIZE AN INSTANCE VARIABLE?
894       Variables  do  not really exist until they are given values.  If you do
895       not initialize a variable when you define it, then you must be sure  to
896       assign  a  value  to  it  (in  the constructor, say, or in some method)
897       before you reference it.
898
899   ARE THERE ANY LIMITATIONS ON INSTANCE VARIABLE NAMES?
900       Just a few.
901
902       First, every Snit  object  has  a  built-in  instance  variable  called
903       options, which should never be redefined.
904
905       Second,  all  names beginning with "Snit_" are reserved for use by Snit
906       internal code.
907
908       Third, instance variable names containing the namespace delimiter  (::)
909       are likely to cause great confusion.
910
911   DO I NEED TO DECLARE MY INSTANCE VARIABLES IN MY METHODS?
912       No. Once you've defined an instance variable in the type definition, it
913       can be used in any instance code (instance  methods,  the  constructor,
914       and  the destructor) without declaration.  This differs from normal Tcl
915       practice, in which all  non-local  variables  in  a  proc  need  to  be
916       declared.
917
918       There  is  a  speed penalty to having all instance variables implicitly
919       available in all instance code.  Even though your code need not declare
920       the  variables explicitly, Snit must still declare them, and that takes
921       time.  If you have ten instance variables, a method that uses  none  of
922       them  must  still  pay  the  declaration  penalty for all ten.  In most
923       cases, the additional runtime cost is negligible.   If  extreme  cases,
924       you might wish to avoid it; there are two methods for doing so.
925
926       The  first is to define a single instance variable, an array, and store
927       all of your instance data in the array.  This way, you're  only  paying
928       the  declaration  penalty  for  one variable--and you probably need the
929       variable most of the time anyway.  This  method  breaks  down  if  your
930       instance  variables  include  multiple arrays; in Tcl 8.5, however, the
931       dict command might come to your rescue.
932
933       The second method is to declare your instance variables  explicitly  in
934       your instance code, while not including them in the type definition:
935
936              snit::type dog {
937                  constructor {} {
938                      variable mood
939
940                      set mood happy
941                  }
942
943                  method setmood {newMood} {
944                      variable mood
945
946                      set mood $newMood
947                  }
948
949                  method getmood {} {
950                      variable mood
951
952                      return $mood
953                  }
954              }
955
956       This allows you to ensure that only the required variables are included
957       in each method, at the cost of longer code and run-time errors when you
958       forget to declare a variable you need.
959
960   HOW DO I PASS AN INSTANCE VARIABLE'S NAME TO ANOTHER OBJECT?
961       In  Tk,  it's  common to pass a widget a variable name; for example, Tk
962       label widgets have a -textvariable  option  which  names  the  variable
963       which  will  contain  the  widget's  text.   This allows the program to
964       update the label's value just by assigning a new value to the variable.
965
966       If you naively pass the instance variable name  to  the  label  widget,
967       you'll  be confused by the result; Tk will assume that the name names a
968       global variable.  Instead, you need to provide a fully-qualified  vari‐
969       able  name.   From  within an instance method or a constructor, you can
970       fully qualify the variable's name using the myvar command:
971
972              snit::widget mywidget {
973                  variable labeltext ""
974
975                  constructor {args} {
976                      # ...
977
978                      label $win.label -textvariable [myvar labeltext]
979
980                      # ...
981                  }
982              }
983
984
985   HOW DO I MAKE AN INSTANCE VARIABLE PUBLIC?
986       Practically speaking, you  don't.   Instead,  you'll  implement  public
987       variables as OPTIONS.  Alternatively, you can write INSTANCE METHODS to
988       set and get the variable's value.
989

OPTIONS

991   WHAT IS AN OPTION?
992       A type's options are the equivalent of what other object-oriented  lan‐
993       guages  would call public member variables or properties: they are data
994       values which can be retrieved and (usually) set by the  clients  of  an
995       object.
996
997       Snit's  implementation  of options follows the Tk model fairly exactly,
998       except that snit::type objects  usually  don't  interact  with  THE  TK
999       OPTION  DATABASE;  snit::widget and snit::widgetadaptor objects, on the
1000       other hand, always do.
1001
1002   HOW DO I DEFINE AN OPTION?
1003       Options are defined in the type definition using the option  statement.
1004       Consider  the following type, to be used in an application that manages
1005       a list of dogs for a pet store:
1006
1007              snit::type dog {
1008                  option -breed -default mongrel
1009                  option -color -default brown
1010                  option -akc   -default 0
1011                  option -shots -default 0
1012              }
1013
1014
1015       According to this, a dog has four notable properties: a breed, a color,
1016       a  flag that says whether it's pedigreed with the American Kennel Club,
1017       and another flag that says whether it has had its shots.   The  default
1018       dog, evidently, is a brown mutt.
1019
1020       There  are a number of options you can specify when defining an option;
1021       if -default is the only one, you can omit the word -default as follows:
1022
1023              snit::type dog {
1024                  option -breed mongrel
1025                  option -color brown
1026                  option -akc   0
1027                  option -shots 0
1028              }
1029
1030
1031       If no -default value is specified, the option's default value  will  be
1032       the empty string (but see THE TK OPTION DATABASE).
1033
1034       The  Snit  man  page  refers to options like these as "locally defined"
1035       options.
1036
1037   HOW CAN A CLIENT SET OPTIONS AT OBJECT CREATION?
1038       The normal convention is that the client may pass any number of options
1039       and their values after the object's name at object creation.  For exam‐
1040       ple, the ::dog command defined in the previous answer can now  be  used
1041       to  create  individual  dogs.   Any or all of the options may be set at
1042       creation time.
1043
1044              % dog spot -breed beagle -color "mottled" -akc 1 -shots 1
1045              ::spot
1046              % dog fido -shots 1
1047              ::fido
1048              %
1049
1050
1051       So ::spot is a pedigreed beagle; ::fido is a typical mutt, but his own‐
1052       ers evidently take care of him, because he's had his shots.
1053
1054       Note:  If  the  type  defines a constructor, it can specify a different
1055       object-creation syntax.  See CONSTRUCTORS for more information.
1056
1057   HOW CAN A CLIENT RETRIEVE AN OPTION'S VALUE?
1058       Retrieve option values using the cget method:
1059
1060              % spot cget -color
1061              mottled
1062              % fido cget -breed
1063              mongrel
1064              %
1065
1066
1067   HOW CAN A CLIENT SET OPTIONS AFTER OBJECT CREATION?
1068       Any number of options may be  set  at  one  time  using  the  configure
1069       instance  method.   Suppose that closer inspection shows that ::fido is
1070       not a brown mongrel, but rather a rare Arctic Boar Hound  of  a  lovely
1071       dun color:
1072
1073              % fido configure -color dun -breed "Arctic Boar Hound"
1074              % fido cget -color
1075              dun
1076              % fido cget -breed
1077              Arctic Boar Hound
1078
1079
1080       Alternatively,  the  configurelist  method  takes a list of options and
1081       values; occasionally this is more convenient:
1082
1083              % set features [list -color dun -breed "Arctic Boar Hound"]
1084              -color dun -breed {Arctic Boar Hound}
1085              % fido configurelist $features
1086              % fido cget -color
1087              dun
1088              % fido cget -breed
1089              Arctic Boar Hound
1090              %
1091
1092
1093       In Tcl 8.5, the * keyword can be used with configure in this case:
1094
1095              % set features [list -color dun -breed "Arctic Boar Hound"]
1096              -color dun -breed {Arctic Boar Hound}
1097              % fido configure {*}$features
1098              % fido cget -color
1099              dun
1100              % fido cget -breed
1101              Arctic Boar Hound
1102              %
1103
1104
1105       The results are the same.
1106
1107   HOW SHOULD AN INSTANCE METHOD ACCESS AN OPTION VALUE?
1108       There are two ways an instance method can set and retrieve an  option's
1109       value.  One is to use the configure and cget methods, as shown below.
1110
1111              % snit::type dog {
1112                  option -weight 10
1113
1114                  method gainWeight {} {
1115                      set wt [$self cget -weight]
1116                      incr wt
1117                      $self configure -weight $wt
1118                  }
1119              }
1120              ::dog
1121              % dog fido
1122              ::fido
1123              % fido cget -weight
1124              10
1125              % fido gainWeight
1126              % fido cget -weight
1127              11
1128              %
1129
1130
1131       Alternatively,  Snit provides a built-in array instance variable called
1132       options.  The indices are the option names; the values are  the  option
1133       values.  The method gainWeight can thus be rewritten as follows:
1134
1135                  method gainWeight {} {
1136                      incr options(-weight)
1137                  }
1138
1139
1140       As  you  can see, using the options variable involves considerably less
1141       typing and is the usual way to do it.  But if you use  -configuremethod
1142       or  -cgetmethod (described in the following answers), you might wish to
1143       use the configure and cget methods anyway, just  so  that  any  special
1144       processing you've implemented is sure to get done.  Also, if the option
1145       is delegated to a component then configure and cget are the only way to
1146       access it without accessing the component directly.  See DELEGATION for
1147       more information.
1148
1149   HOW CAN I MAKE AN OPTION READ-ONLY?
1150       Define the option with -readonly yes.
1151
1152       Suppose you've got an option that determines how instances of your type
1153       are constructed; it must be set at creation time, after which it's con‐
1154       stant.  For example, a dog never changes its breed; it might  or  might
1155       not  have  had  its  shots,  and  if not can have them at a later time.
1156       -breed should be read-only, but -shots should not be.
1157
1158              % snit::type dog {
1159                  option -breed -default mongrel -readonly yes
1160                  option -shots -default no
1161              }
1162              ::dog
1163              % dog fido -breed retriever
1164              ::fido
1165              % fido configure -shots yes
1166              % fido configure -breed terrier
1167              option -breed can only be set at instance creation
1168              %
1169
1170
1171   HOW CAN I CATCH ACCESSES TO AN OPTION'S VALUE?
1172       Define a -cgetmethod for the option.
1173
1174   WHAT IS A -CGETMETHOD?
1175       A -cgetmethod is a method that's called whenever the  related  option's
1176       value is queried via the cget instance method.  The handler can compute
1177       the option's value, retrieve it from a database, or  do  anything  else
1178       you'd like it to do.
1179
1180       Here's  what  the  default  behavior would look like if written using a
1181       -cgetmethod:
1182
1183              snit::type dog {
1184                  option -color -default brown -cgetmethod GetOption
1185
1186                  method GetOption {option} {
1187                      return $options($option)
1188                  }
1189              }
1190
1191
1192       Any instance method can be used, provided that it takes  one  argument,
1193       the name of the option whose value is to be retrieved.
1194
1195   HOW CAN I CATCH CHANGES TO AN OPTION'S VALUE?
1196       Define a -configuremethod for the option.
1197
1198   WHAT IS A -CONFIGUREMETHOD?
1199       A  -configuremethod  is  a  method  that's  called whenever the related
1200       option is given a new value via the configure or configurelist instance
1201       methods.  The  method can pass the value on to some other object, store
1202       it in a database, or do anything else you'd like it to do.
1203
1204       Here's what the default configuration behavior would look like if writ‐
1205       ten using a -configuremethod:
1206
1207              snit::type dog {
1208                  option -color -default brown -configuremethod SetOption
1209
1210                  method SetOption {option value} {
1211                      set options($option) $value
1212                  }
1213              }
1214
1215
1216       Any  instance method can be used, provided that it takes two arguments,
1217       the name of the option and the new value.
1218
1219       Note that if your method doesn't store the value in the options  array,
1220       the options array won't get updated.
1221
1222   HOW CAN I VALIDATE AN OPTION'S VALUE?
1223       Define a -validatemethod.
1224
1225   WHAT IS A -VALIDATEMETHOD?
1226       A -validatemethod is a method that's called whenever the related option
1227       is given a new value via the configure or configurelist instance  meth‐
1228       ods.   It's  the  method's  responsibility to determine whether the new
1229       value is valid, and throw an error if it isn't.   The  -validatemethod,
1230       if  any,  is called before the value is stored in the options array; in
1231       particular, it's called before the -configuremethod, if any.
1232
1233       For example, suppose an option always takes a Boolean value.   You  can
1234       ensure that the value is in fact a valid Boolean like this:
1235
1236              % snit::type dog {
1237                  option -shots -default no -validatemethod BooleanOption
1238
1239                  method BooleanOption {option value} {
1240                      if {![string is boolean -strict $value]} {
1241                          error "expected a boolean value, got \"$value\""
1242                      }
1243                  }
1244              }
1245              ::dog
1246              % dog fido
1247              % fido configure -shots yes
1248              % fido configure -shots NotABooleanValue
1249              expected a boolean value, got "NotABooleanValue"
1250              %
1251
1252       Note  that  the same -validatemethod can be used to validate any number
1253       of boolean options.
1254
1255       Any method can be a -validatemethod provided that it  takes  two  argu‐
1256       ments, the option name and the new option value.
1257

TYPE VARIABLES

1259   WHAT IS A TYPE VARIABLE?
1260       A  type  variable  is  a  private  variable associated with a Snit type
1261       rather than with a particular instance of the type.  In C++  and  Java,
1262       the  term  static  member  variable  is used for the same notion.  Type
1263       variables can be scalars or arrays.
1264
1265   HOW IS A SCALAR TYPE VARIABLE DEFINED?
1266       Scalar type variables are defined in  the  type  definition  using  the
1267       typevariable  statement.  You can simply name it, or you can initialize
1268       it with a value:
1269
1270              snit::type mytype {
1271                  # Define variable "greeting" and initialize it with "Howdy!"
1272                  typevariable greeting "Howdy!"
1273              }
1274
1275
1276       Every object of type mytype now has access to a single variable  called
1277       greeting.
1278
1279   HOW IS AN ARRAY-VALUED TYPE VARIABLE DEFINED?
1280       Array-valued  type  variables  are  also defined using the typevariable
1281       command; to initialize them, include the -array option:
1282
1283              snit::type mytype {
1284                  # Define typearray variable "greetings"
1285                  typevariable greetings -array {
1286                      formal "Good Evening"
1287                      casual "Howdy!"
1288                  }
1289              }
1290
1291
1292   WHAT HAPPENS IF I DON'T INITIALIZE A TYPE VARIABLE?
1293       Variables do not really exist until they are given values.  If  you  do
1294       not  initialize a variable when you define it, then you must be sure to
1295       assign a value to it (in the type constructor, say) before  you  refer‐
1296       ence it.
1297
1298   ARE THERE ANY LIMITATIONS ON TYPE VARIABLE NAMES?
1299       Type variable names have the same restrictions as the names of INSTANCE
1300       VARIABLES do.
1301
1302   DO I NEED TO DECLARE MY TYPE VARIABLES IN MY METHODS?
1303       No. Once you've defined a type variable in the type definition, it  can
1304       be  used in INSTANCE METHODS or TYPE METHODS without declaration.  This
1305       differs from normal Tcl practice, in which all non-local variables in a
1306       proc need to be declared.
1307
1308       Type  variables  are subject to the same speed/readability tradeoffs as
1309       instance variables; see Do I need to declare my instance  variables  in
1310       my methods?
1311
1312   HOW DO I PASS A TYPE VARIABLE'S NAME TO ANOTHER OBJECT?
1313       In  Tk,  it's  common to pass a widget a variable name; for example, Tk
1314       label widgets have a -textvariable  option  which  names  the  variable
1315       which  will  contain  the  widget's  text.   This allows the program to
1316       update the label's value just by assigning a new value to the variable.
1317
1318       If you naively pass a type variable name to the label widget, you'll be
1319       confused  by  the  result;  Tk will assume that the name names a global
1320       variable.  Instead, you need  to  provide  a  fully-qualified  variable
1321       name.   From  within an instance method or a constructor, you can fully
1322       qualify the type variable's name using the mytypevar command:
1323
1324              snit::widget mywidget {
1325                  typevariable labeltext ""
1326
1327                  constructor {args} {
1328                      # ...
1329
1330                      label $win.label -textvariable [mytypevar labeltext]
1331
1332                      # ...
1333                  }
1334              }
1335
1336
1337   HOW DO I MAKE A TYPE VARIABLE PUBLIC?
1338       There are two ways to do this.  The preferred way is to write a pair of
1339       TYPE METHODS to set and query the type variable's value.
1340
1341       Type  variables  are stored in the type's namespace, which has the same
1342       name as the type itself.  Thus, you can also publicize the  type  vari‐
1343       able's  name  in  your  documentation  so  that  clients  can access it
1344       directly.  For example,
1345
1346              snit::type mytype {
1347                  typevariable myvariable
1348              }
1349
1350              set ::mytype::myvariable "New Value"
1351
1352

TYPE METHODS

1354   WHAT IS A TYPE METHOD?
1355       A type method is a procedure associated with  the  type  itself  rather
1356       than with any specific instance of the type, and called as a subcommand
1357       of the type command.
1358
1359   HOW DO I DEFINE A TYPE METHOD?
1360       Type methods are defined in the type definition  using  the  typemethod
1361       statement:
1362
1363              snit::type dog {
1364                  # List of pedigreed dogs
1365                  typevariable pedigreed
1366
1367                  typemethod pedigreedDogs {} {
1368                      return $pedigreed
1369                  }
1370              }
1371
1372
1373       Suppose  the  dog  type  maintains a list of the names of the dogs that
1374       have pedigrees.  The pedigreedDogs type method returns this list.
1375
1376       The typemethod statement looks just like a normal Tcl proc, except that
1377       it  appears  in a snit::type definition.  Notice that every type method
1378       gets an implicit argument called type, which contains the  fully-quali‐
1379       fied type name.
1380
1381   HOW DOES A CLIENT CALL A TYPE METHOD?
1382       The  type  method name becomes a subcommand of the type's command.  For
1383       example, assuming that the constructor adds each pedigreed dog  to  the
1384       list of pedigreedDogs,
1385
1386              snit::type dog {
1387                  option -pedigreed 0
1388
1389                  # List of pedigreed dogs
1390                  typevariable pedigreed
1391
1392                  typemethod pedigreedDogs {} {
1393                      return $pedigreed
1394                  }
1395
1396                  # ...
1397              }
1398
1399              dog spot -pedigreed 1
1400              dog fido
1401
1402              foreach dog [dog pedigreedDogs] { ... }
1403
1404
1405   ARE THERE ANY LIMITATIONS ON TYPE METHOD NAMES?
1406       Not  really,  so long as you avoid the standard type method names: cre‐
1407       ate, destroy, and info.
1408
1409   HOW DO I MAKE A TYPE METHOD PRIVATE?
1410       It's sometimes useful to define private type  methods,  that  is,  type
1411       methods intended to be called only by other type or instance methods of
1412       the same object.
1413
1414       Snit doesn't implement any access control on type methods;  by  conven‐
1415       tion,  the  names of public methods begin with a lower-case letter, and
1416       the names of private methods begin with an upper-case letter.
1417
1418       Alternatively, a Snit proc can be used as a private  type  method;  see
1419       PROCS.
1420
1421   ARE THERE ANY LIMITATIONS ON TYPE METHOD ARGUMENTS?
1422       Method  argument  lists  are defined just like normal Tcl proc argument
1423       lists; in particular, they can include arguments  with  default  values
1424       and the args argument.
1425
1426       However,  every  type method is called with an implicit argument called
1427       type that contains the name of the type  command.   In  addition,  type
1428       methods  should  by  convention  avoid using the names of the arguments
1429       implicitly defined for INSTANCE METHODS.
1430
1431   HOW DOES AN INSTANCE OR TYPE METHOD CALL A TYPE METHOD?
1432       If an instance or type method needs to call a type  method,  it  should
1433       use $type to do so:
1434
1435              snit::type dog {
1436
1437                  typemethod pedigreedDogs {} { ... }
1438
1439                  typemethod printPedigrees {} {
1440                      foreach obj [$type pedigreedDogs] { ... }
1441                  }
1442              }
1443
1444
1445   HOW DO I PASS A TYPE METHOD AS A CALLBACK?
1446       It's  common in Tcl to pass a snippet of code to another object, for it
1447       to call later.  Because types cannot be renamed, you can just  use  the
1448       type name, or, if the callback is registered from within a type method,
1449       type.  For example, suppose we want to print a list of  pedigreed  dogs
1450       when a Tk button is pushed:
1451
1452              button .btn -text "Pedigrees" -command [list dog printPedigrees]
1453              pack .btn
1454
1455       Alternatively,   from   a  method  or  type  method  you  can  use  the
1456       mytypemethod command, just as you would use mymethod to define a  call‐
1457       back command for INSTANCE METHODS.
1458
1459   CAN TYPE METHODS BE HIERARCHICAL?
1460       Yes,  you  can define hierarchical type methods in just the same way as
1461       you can define hierarchical instance methods.  See INSTANCE METHODS for
1462       more.
1463

PROCS

1465   WHAT IS A PROC?
1466       A  Snit proc is really just a Tcl proc defined within the type's names‐
1467       pace.  You can use procs for private code that  isn't  related  to  any
1468       particular instance.
1469
1470   HOW DO I DEFINE A PROC?
1471       Procs are defined by including a proc statement in the type definition:
1472
1473              snit::type mytype {
1474                  # Pops and returns the first item from the list stored in the
1475                  # listvar, updating the listvar
1476                 proc pop {listvar} { ... }
1477
1478                 # ...
1479              }
1480
1481
1482   ARE THERE ANY LIMITATIONS ON PROC NAMES?
1483       Any  name  can  be used, so long as it does not begin with Snit_; names
1484       beginning with Snit_ are reserved for Snit's  own  use.   However,  the
1485       wise  programmer will avoid proc names (set, list, if, etc.) that would
1486       shadow standard Tcl command names.
1487
1488       proc names, being private, should begin with a capital letter according
1489       to  convention;  however, as there are typically no public procs in the
1490       type's namespace it doesn't matter much either way.
1491
1492   HOW DOES A METHOD CALL A PROC?
1493       Just like it calls any Tcl command.  For example,
1494
1495              snit::type mytype {
1496                  # Pops and returns the first item from the list stored in the
1497                  # listvar, updating the listvar
1498                  proc pop {listvar} { ... }
1499
1500                  variable requestQueue {}
1501
1502                  # Get one request from the queue and process it.
1503                  method processRequest {} {
1504                      set req [pop requestQueue]
1505                  }
1506              }
1507
1508
1509   HOW CAN I PASS A PROC TO ANOTHER OBJECT AS A CALLBACK?
1510       The myproc command returns a callback command for  the  proc,  just  as
1511       mymethod does for a method.
1512

TYPE CONSTRUCTORS

1514   WHAT IS A TYPE CONSTRUCTOR?
1515       A  type  constructor  is  a body of code that initializes the type as a
1516       whole, rather like a C++ static initializer.  The body of a  type  con‐
1517       structor is executed once when the type is defined, and never again.
1518
1519       A type can have at most one type constructor.
1520
1521   HOW DO I DEFINE A TYPE CONSTRUCTOR?
1522       A type constructor is defined by using the typeconstructor statement in
1523       the type definition.  For example, suppose the type uses an  array-val‐
1524       ued  type variable as a look-up table, and the values in the array have
1525       to be computed at start-up.
1526
1527              % snit::type mytype {
1528                  typevariable lookupTable
1529
1530                  typeconstructor {
1531                      array set lookupTable {key value...}
1532                  }
1533              }
1534
1535

CONSTRUCTORS

1537   WHAT IS A CONSTRUCTOR?
1538       In object-oriented programming, an object's constructor is  responsible
1539       for  initializing the object completely at creation time. The construc‐
1540       tor receives the list of options passed  to  the  snit::type  command's
1541       create  method  and  can then do whatever it likes.  That might include
1542       computing instance variable values, reading data from  files,  creating
1543       other objects, updating type and instance variables, and so forth.
1544
1545       The  constructor's  return  value  is ignored (unless it's an error, of
1546       course).
1547
1548   HOW DO I DEFINE A CONSTRUCTOR?
1549       A constructor is defined by using the constructor statement in the type
1550       definition.   Suppose that it's desired to keep a list of all pedigreed
1551       dogs.  The list can be maintained in a type variable and retrieved by a
1552       type  method.   Whenever  a  dog  is  created, it can add itself to the
1553       list--provided that it's registered with the American Kennel Club.
1554
1555              % snit::type dog {
1556                  option -akc 0
1557
1558                  typevariable akcList {}
1559
1560                  constructor {args} {
1561                      $self configurelist $args
1562
1563                      if {$options(-akc)} {
1564                          lappend akcList $self
1565                      }
1566                  }
1567
1568                  typemethod akclist {} {
1569                      return $akcList
1570                  }
1571              }
1572              ::dog
1573              % dog spot -akc 1
1574              ::spot
1575              % dog fido
1576              ::fido
1577              % dog akclist
1578              ::spot
1579              %
1580
1581
1582   WHAT DOES THE DEFAULT CONSTRUCTOR DO?
1583       If you don't provide a constructor explicitly, you get the default con‐
1584       structor,  which  is  identical  to  the explicitly-defined constructor
1585       shown here:
1586
1587              snit::type dog {
1588                  constructor {args} {
1589                      $self configurelist $args
1590                  }
1591              }
1592
1593
1594       When the constructor is called, args will be set to the list  of  argu‐
1595       ments  that  follow  the  object's name.  The constructor is allowed to
1596       interpret this list any way it chooses; the  normal  convention  is  to
1597       assume  that  it's  a  list of option names and values, as shown in the
1598       example above.  If you simply want  to  save  the  option  values,  you
1599       should use the configurelist method, as shown.
1600
1601   CAN I CHOOSE A DIFFERENT SET OF ARGUMENTS FOR THE CONSTRUCTOR?
1602       Yes, you can.  For example, suppose we wanted to be sure that the breed
1603       was explicitly stated for every dog at creation time, and  couldn't  be
1604       changed thereafter.  One way to do that is as follows:
1605
1606              % snit::type dog {
1607                  variable breed
1608
1609                  option -color brown
1610                  option -akc 0
1611
1612                  constructor {theBreed args} {
1613                      set breed $theBreed
1614                      $self configurelist $args
1615                  }
1616
1617                  method breed {} { return $breed }
1618              }
1619              ::dog
1620              % dog spot dalmatian -color spotted -akc 1
1621              ::spot
1622              % spot breed
1623              dalmatian
1624
1625
1626       The  drawback  is  that  this syntax is non-standard, and may limit the
1627       compatibility of your new type with other people's code.  For  example,
1628       Snit  assumes that it can create COMPONENTS using the standard creation
1629       syntax.
1630
1631   ARE THERE ANY LIMITATIONS ON CONSTRUCTOR ARGUMENTS?
1632       Constructor argument lists are subject to the same limitations as those
1633       on instance method argument lists.  It has the same implicit arguments,
1634       and can contain default values and the args argument.
1635
1636   IS THERE ANYTHING SPECIAL ABOUT WRITING THE CONSTRUCTOR?
1637       Yes.  Writing the  constructor  can  be  tricky  if  you're  delegating
1638       options  to  components,  and  there  are  specific  issues relating to
1639       snit::widgets and snit::widgetadaptors.  See DELEGATION, WIDGETS,  WID‐
1640       GET ADAPTORS, and THE TK OPTION DATABASE.
1641

DESTRUCTORS

1643   WHAT IS A DESTRUCTOR?
1644       A  destructor  is a special kind of method that's called when an object
1645       is destroyed.  It's responsible for doing any necessary  clean-up  when
1646       the  object  goes  away:  destroying  COMPONENTS, closing files, and so
1647       forth.
1648
1649   HOW DO I DEFINE A DESTRUCTOR?
1650       Destructors are defined by using the destructor statement in  the  type
1651       definition.
1652
1653       Suppose  we're maintaining a list of pedigreed dogs; then we'll want to
1654       remove dogs from it when they are destroyed.
1655
1656              snit::type dog {
1657                  option -akc 0
1658
1659                  typevariable akcList {}
1660
1661                  constructor {args} {
1662                      $self configurelist $args
1663
1664                      if {$options(-akc)} {
1665                          lappend akcList $self
1666                      }
1667                  }
1668
1669                  destructor {
1670                      set ndx [lsearch $akcList $self]
1671
1672                      if {$ndx != -1} {
1673                          set akcList [lreplace $akcList $ndx $ndx]
1674                      }
1675                  }
1676
1677                  typemethod akclist {} {
1678                      return $akcList
1679                  }
1680              }
1681
1682
1683   ARE THERE ANY LIMITATIONS ON DESTRUCTOR ARGUMENTS?
1684       Yes; a destructor has no explicit arguments.
1685
1686   WHAT IMPLICIT ARGUMENTS ARE PASSED TO THE DESTRUCTOR?
1687       The destructor gets the same implicit  arguments  that  are  passed  to
1688       INSTANCE METHODS: type, selfns, win, and self.
1689
1690   MUST COMPONENTS BE DESTROYED EXPLICITLY?
1691       Yes and no.
1692
1693       Any Tk widgets created by a snit::widget or snit::widgetadaptor will be
1694       destroyed automatically by Tk when  the  megawidget  is  destroyed,  in
1695       keeping  with  normal  Tk behavior (destroying a parent widget destroys
1696       the whole tree).
1697
1698       Components  of  normal  snit::types,  on  the  other  hand,  are  never
1699       destroyed automatically, nor are non-widget components of Snit megawid‐
1700       gets.  If your object creates them in its constructor, then  it  should
1701       generally destroy them in its destructor.
1702
1703   IS THERE ANY SPECIAL ABOUT WRITING A DESTRUCTOR?
1704       Yes.  If an object's constructor throws an error, the object's destruc‐
1705       tor will be called to clean up; this means that the object might not be
1706       completely  constructed  when the destructor is called.  This can cause
1707       the destructor to throw its own error; the result is  usually  mislead‐
1708       ing,  confusing,  and unhelpful.  Consequently, it's important to write
1709       your destructor so that it's fail-safe.
1710
1711       For example, a dog might create a tail component;  the  component  will
1712       need  to  be  destroyed.  But suppose there's an error while processing
1713       the creation options--the destructor will be called, and there will  be
1714       no  tail  to  destroy.  The simplest solution is generally to catch and
1715       ignore any errors while destroying components.
1716
1717              snit::type dog {
1718                  component tail
1719
1720                  constructor {args} {
1721                      $self configurelist $args
1722
1723                      set tail [tail %AUTO%]
1724                  }
1725
1726                  destructor {
1727                      catch {$tail destroy}
1728                  }
1729              }
1730
1731

COMPONENTS

1733   WHAT IS A COMPONENT?
1734       Often an object will create and manage a number of  other  objects.   A
1735       Snit megawidget, for example, will often create a number of Tk widgets.
1736       These objects are part of the main object; it is composed of  them,  so
1737       they are called components of the object.
1738
1739       But Snit also has a more precise meaning for COMPONENT.  The components
1740       of a Snit object are those objects to which methods or options  can  be
1741       delegated.  (See DELEGATION for more information about delegation.)
1742
1743   HOW DO I DECLARE A COMPONENT?
1744       First,  you must decide what role a component plays within your object,
1745       and give the role a name.  Then, you declare the  component  using  its
1746       role  name  and  the  component  statement.   The  component  statement
1747       declares an instance variable which is used to  store  the  component's
1748       command name when the component is created.
1749
1750       For  example, suppose your dog object creates a tail object (the better
1751       to wag with, no doubt):
1752
1753              snit::type dog {
1754                  component mytail
1755
1756                  constructor {args} {
1757                      # Create and save the component's command
1758                      set mytail [tail %AUTO% -partof $self]
1759                      $self configurelist $args
1760                  }
1761
1762                  method wag {} {
1763                      $mytail wag
1764                  }
1765              }
1766
1767
1768       As shown here, it doesn't matter what the tail object's real  name  is;
1769       the dog object refers to it by its component name.
1770
1771       The  above  example  shows  one  way  to delegate the wag method to the
1772       mytail component; see DELEGATION for an easier way.
1773
1774   HOW IS A COMPONENT NAMED?
1775       A component has two names.  The first name is  that  of  the  component
1776       variable;  this  represents  the role the component object plays within
1777       the Snit object.  This is the component name proper, and  is  the  name
1778       used  to  refer  to the component within Snit code.  The second name is
1779       the name of the actual component object created by  the  Snit  object's
1780       constructor.   This  second  name  is always a Tcl command name, and is
1781       referred to as the component's object name.
1782
1783       In the example in the previous question, the component name is  mytail;
1784       the  mytail  component's  object  name  is chosen automatically by Snit
1785       since %AUTO% was used when the component object was created.
1786
1787   ARE THERE ANY LIMITATIONS ON COMPONENT NAMES?
1788       Yes.  snit::widget and snit::widgetadaptor objects have a special  com‐
1789       ponent  called  the  hull component; thus, the name hull should be used
1790       for no other purpose.
1791
1792       Otherwise, since component names are in fact  instance  variable  names
1793       they must follow the rules for INSTANCE VARIABLES.
1794
1795   WHAT IS AN OWNED COMPONENT?
1796       An  owned  component  is a component whose object command's lifetime is
1797       controlled by the snit::type or snit::widget.
1798
1799       As stated above, a component is an object to which our object can dele‐
1800       gate  methods  or options.  Under this definition, our object will usu‐
1801       ally create its component objects, but not necessarily.   Consider  the
1802       following:  a dog object has a tail component; but tail knows that it's
1803       part of the dog:
1804
1805              snit::type dog {
1806                  component mytail
1807
1808                  constructor {args} {
1809                      set mytail [tail %AUTO% -partof $self]
1810                      $self configurelist $args
1811                  }
1812
1813                  destructor {
1814                      catch {$mytail destroy}
1815                  }
1816
1817                  delegate method wagtail to mytail as wag
1818
1819                  method bark {} {
1820                      return "$self barked."
1821                  }
1822              }
1823
1824               snit::type tail {
1825                   component mydog
1826                   option -partof -readonly yes
1827
1828                   constructor {args} {
1829                       $self configurelist $args
1830                       set mydog $options(-partof)
1831                   }
1832
1833                   method wag {} {
1834                       return "Wag, wag."
1835                   }
1836
1837                   method pull {} {
1838                       $mydog bark
1839                   }
1840               }
1841
1842       Thus, if you ask a dog to wag its tail, it tells its tail to  wag;  and
1843       if  you  pull  the dog's tail, the tail tells the dog to bark.  In this
1844       scenario, the tail is a component of the dog, and the dog is  a  compo‐
1845       nent  of  the  tail,  but  the  dog owns the tail and not the other way
1846       around.
1847
1848   WHAT DOES THE INSTALL COMMAND DO?
1849       The install command creates an owned component using a  specified  com‐
1850       mand, and assigns the result to the component's instance variable.  For
1851       example:
1852
1853              snit::type dog {
1854                  component mytail
1855
1856                  constructor {args} {
1857                      # set mytail [tail %AUTO% -partof $self]
1858                      install mytail using tail %AUTO% -partof $self
1859                      $self configurelist $args
1860                  }
1861              }
1862
1863       In a snit::type's code, the install command shown above  is  equivalent
1864       to the set mytail command that's commented out.  In a snit::widget's or
1865       snit::widgetadaptor's, code, however, the install command also  queries
1866       THE  TK  OPTION  DATABASE  and  initializes the new component's options
1867       accordingly.  For consistency, it's a good idea to get in the habit  of
1868       using install for all owned components.
1869
1870   MUST OWNED COMPONENTS BE CREATED IN THE CONSTRUCTOR?
1871       No,  not  necessarily.   In fact, there's no reason why an object can't
1872       destroy and recreate a component multiple times over its own lifetime.
1873
1874   ARE THERE ANY LIMITATIONS ON COMPONENT OBJECT NAMES?
1875       Yes.
1876
1877       Component objects which are Tk widgets or megawidgets must  have  valid
1878       Tk window names.
1879
1880       Component objects which are not widgets or megawidgets must have fully-
1881       qualified command names, i.e., names which include the  full  namespace
1882       of the command.  Note that Snit always creates objects with fully qual‐
1883       ified names.
1884
1885       Next, the object names of components and owned by your object  must  be
1886       unique.   This  is no problem for widget components, since widget names
1887       are always unique; but consider the following code:
1888
1889              snit::type tail { ... }
1890
1891              snit::type dog {
1892                  delegate method wag to mytail
1893
1894                  constructor {} {
1895                      install mytail using tail mytail
1896                  }
1897              }
1898
1899
1900       This code uses the component name,  mytail,  as  the  component  object
1901       name.  This is not good, and here's why: Snit instance code executes in
1902       the Snit type's namespace.  In this case, the mytail component is  cre‐
1903       ated   in   the   ::dog::  namespace,  and  will  thus  have  the  name
1904       ::dog::mytail.
1905
1906       Now, suppose you create two dogs.  Both dogs will attempt to  create  a
1907       tail called ::dog::mytail.  The first will succeed, and the second will
1908       fail, since Snit won't let you create an object if its name is  already
1909       a command.  Here are two ways to avoid this situation:
1910
1911       First,  if the component type is a snit::type you can specify %AUTO% as
1912       its name, and be guaranteed to get a unique name.  This is  the  safest
1913       thing to do:
1914
1915                  install mytail using tail %AUTO%
1916
1917
1918       If  the  component type isn't a snit::type you can create the component
1919       in the object's instance namespace:
1920
1921                  install mytail using tail ${selfns}::mytail
1922
1923
1924       Make sure you pick a unique name within the instance namespace.
1925
1926   MUST I DESTROY THE COMPONENTS I OWN?
1927       That depends.  When a parent widget is destroyed, all child widgets are
1928       destroyed  automatically.  Thus,  if  your  object is a snit::widget or
1929       snit::widgetadaptor you don't need to destroy any components  that  are
1930       widgets, because they will generally be children or descendants of your
1931       megawidget.
1932
1933       If your object is an instance of snit::type, though, none of its  owned
1934       components will be destroyed automatically, nor will be non-widget com‐
1935       ponents of a snit::widget be destroyed automatically.  All  such  owned
1936       components  must be destroyed explicitly, or they won't be destroyed at
1937       all.
1938
1939   CAN I EXPOSE A COMPONENT'S OBJECT COMMAND AS PART OF MY INTERFACE?
1940       Yes, and there are two ways to do it.  The most appropriate way is usu‐
1941       ally  to use DELEGATION.  Delegation allows you to pass the options and
1942       methods you specify along to particular components.   This  effectively
1943       hides  the  components  from  the  users of your type, and ensures good
1944       encapsulation.
1945
1946       However, there are times when it's appropriate, not to mention simpler,
1947       just to make the entire component part of your type's public interface.
1948
1949   HOW DO I EXPOSE A COMPONENT'S OBJECT COMMAND?
1950       When you declare the component, specify the component statement's -pub‐
1951       lic option.  The value of this option is the name  of  a  method  which
1952       will be delegated to your component's object command.
1953
1954       For example, supposed you've written a combobox megawidget which owns a
1955       listbox widget, and you want to make  the  listbox's  entire  interface
1956       public.  You can do it like this:
1957
1958              snit::widget combobox {
1959                   component listbox -public listbox
1960
1961                   constructor {args} {
1962                       install listbox using listbox $win.listbox ....
1963                   }
1964              }
1965
1966              combobox .mycombo
1967              .mycombo listbox configure -width 30
1968
1969
1970       Your  comobox  widget, .mycombo, now has a listbox method which has all
1971       of the same subcommands as the listbox widget itself.  Thus, the  above
1972       code sets the listbox component's width to 30.
1973
1974       Usually  you'll  let the method name be the same as the component name;
1975       however, you can name it anything you like.
1976

TYPE COMPONENTS

1978   WHAT IS A TYPE COMPONENT?
1979       A type component is a component that belongs to the type itself instead
1980       of to a particular instance of the type.  The relationship between com‐
1981       ponents and type components is the same  as  the  relationship  between
1982       INSTANCE  VARIABLES and TYPE VARIABLES.  Both INSTANCE METHODS and TYPE
1983       METHODS can be delegated to type components.
1984
1985       Once you understand COMPONENTS and DELEGATION, type components are just
1986       more of the same.
1987
1988   HOW DO I DECLARE A TYPE COMPONENT?
1989       Declare  a  type component using the typecomponent statement.  It takes
1990       the same options (-inherit and  -public)  as  the  component  statement
1991       does,  and  defines a type variable to hold the type component's object
1992       command.
1993
1994       Suppose in your model you've got many dogs, but only one  veterinarian.
1995       You might make the veterinarian a type component.
1996
1997              snit::type veterinarian { ... }
1998
1999              snit::type dog {
2000                  typecomponent vet
2001
2002                  # ...
2003              }
2004
2005
2006   HOW DO I INSTALL A TYPE COMPONENT?
2007       Just  use  the  set command to assign the component's object command to
2008       the type component.  Because types (even snit::widget  types)  are  not
2009       widgets,  and  do  not  have  options anyway, the extra features of the
2010       install command are not needed.
2011
2012       You'll usually install type components  in  the  type  constructor,  as
2013       shown here:
2014
2015              snit::type veterinarian { ... }
2016
2017              snit::type dog {
2018                  typecomponent vet
2019
2020                  typeconstructor {
2021                      set vet [veterinarian %AUTO%]
2022                  }
2023              }
2024
2025
2026   ARE THERE ANY LIMITATIONS ON TYPE COMPONENT NAMES?
2027       Yes, the same as on INSTANCE VARIABLES, TYPE VARIABLES, and normal COM‐
2028       PONENTS.
2029

DELEGATION

2031   WHAT IS DELEGATION?
2032       Delegation, simply put, is when you pass a task you've  been  given  to
2033       one  of  your  assistants.   (You do have assistants, don't you?)  Snit
2034       objects can do the same thing.  The following example shows one way  in
2035       which  the  dog  object can delegate its wag method and its -taillength
2036       option to its tail component.
2037
2038              snit::type dog {
2039                  variable mytail
2040
2041                  option -taillength -configuremethod SetTailOption -cgetmethod GetTailOption
2042
2043                  method SetTailOption {option value} {
2044                       $mytail configure $option $value
2045                  }
2046
2047                  method GetTailOption {option} {
2048                       $mytail cget $option
2049                  }
2050
2051                  method wag {} {
2052                      $mytail wag
2053                  }
2054
2055                  constructor {args} {
2056                      install mytail using tail %AUTO% -partof $self
2057                      $self configurelist $args
2058                  }
2059
2060              }
2061
2062
2063       This is the hard way to do it, by it demonstrates  what  delegation  is
2064       all about.  See the following answers for the easy way to do it.
2065
2066       Note  that the constructor calls the configurelist method after it cre‐
2067       ates its tail; otherwise, if -taillength appeared in the list  of  args
2068       we'd get an error.
2069
2070   HOW CAN I DELEGATE A METHOD TO A COMPONENT OBJECT?
2071       Delegation occurs frequently enough that Snit makes it easy. Any method
2072       can be delegated to any component or type component by placing a single
2073       delegate  statement  in  the type definition.  (See COMPONENTS and TYPE
2074       COMPONENTS for more information about component names.)
2075
2076       For example, here's a much better way to delegate the dog object's  wag
2077       method:
2078
2079              % snit::type dog {
2080                  delegate method wag to mytail
2081
2082                  constructor {} {
2083                      install mytail using tail %AUTO%
2084                  }
2085              }
2086              ::dog
2087              % snit::type tail {
2088                  method wag {} { return "Wag, wag, wag."}
2089              }
2090              ::tail
2091              % dog spot
2092              ::spot
2093              % spot wag
2094              Wag, wag, wag.
2095
2096
2097       This  code  has  the  same  effect as the code shown under the previous
2098       question: when a dog's wag method is called, the call and its arguments
2099       are passed along automatically to the tail object.
2100
2101       Note  that  when  a component is mentioned in a delegate statement, the
2102       component's instance variable is  defined  implicitly.   However,  it's
2103       still good practice to declare it explicitly using the component state‐
2104       ment.
2105
2106       Note also that you can define a method name using the method statement,
2107       or you can define it using delegate; you can't do both.
2108
2109   CAN I DELEGATE TO A METHOD WITH A DIFFERENT NAME?
2110       Suppose  you  wanted to delegate the dog's wagtail method to the tail's
2111       wag method.  After all you wag the tail,  not  the  dog.   It's  easily
2112       done:
2113
2114              snit::type dog {
2115                  delegate method wagtail to mytail as wag
2116
2117                  constructor {args} {
2118                      install mytail using tail %AUTO% -partof $self
2119                      $self configurelist $args
2120                  }
2121              }
2122
2123
2124   CAN I DELEGATE TO A METHOD WITH ADDITIONAL ARGUMENTS?
2125       Suppose  the tail's wag method takes as an argument the number of times
2126       the tail should be wagged.  You want  to  delegate  the  dog's  wagtail
2127       method  to  the  tail's  wag method, specifying that the tail should be
2128       wagged exactly three times.  This is easily done, too:
2129
2130              snit::type dog {
2131                  delegate method wagtail to mytail as {wag 3}
2132                  # ...
2133              }
2134
2135              snit::type tail {
2136                  method wag {count} {
2137                      return [string repeat "Wag " $count]
2138                  }
2139                  # ...
2140              }
2141
2142
2143   CAN I DELEGATE A METHOD TO SOMETHING OTHER THAN AN OBJECT?
2144       Normal method delegation assumes that you're  delegating  a  method  (a
2145       subcommand  of an object command) to a method of another object (a sub‐
2146       command of a different object command).  But not all Tcl objects follow
2147       Tk  conventions,  and not everything you'd to which you'd like to dele‐
2148       gate a method is necessary an object.  Consequently, Snit makes it easy
2149       to  delegate  a method to pretty much anything you like using the dele‐
2150       gate statement's using clause.
2151
2152       Suppose your dog simulation stores dogs in a database, each  dog  as  a
2153       single record.  The database API you're using provides a number of com‐
2154       mands to manage records; each takes the record ID (a string you choose)
2155       as  its  first  argument.  For example, saverec saves a record.  If you
2156       let the record ID be the name of the dog object, you can  delegate  the
2157       dog's save method to the saverec command as follows:
2158
2159              snit::type dog {
2160                  delegate method save using {saverec %s}
2161              }
2162
2163       The  %s  is  replaced  with  the  instance name when the save method is
2164       called; any additional arguments are the appended to the resulting com‐
2165       mand.
2166
2167       The  using clause understands a number of other %-conversions; in addi‐
2168       tion to the instance name, you can substitute in the method name  (%m),
2169       the  type  name  (%t),  the instance namespace (%n), the Tk window name
2170       (%w), and, if a component or typecomponent name was given in the  dele‐
2171       gate statement, the component's object command (%c).
2172
2173   HOW CAN I DELEGATE A METHOD TO A TYPE COMPONENT OBJECT?
2174       Just  exactly  as you would to a component object.  The delegate method
2175       statement accepts both component and type component  names  in  its  to
2176       clause.
2177
2178   HOW CAN I DELEGATE A TYPE METHOD TO A TYPE COMPONENT OBJECT?
2179       Use  the delegate typemethod statement.  It works like delegate method,
2180       with these differences: first, it defines a type method instead  of  an
2181       instance  method;  second,  the using clause ignores the %s, %n, and %w
2182       %-conversions.
2183
2184       Naturally, you can't delegate a  type  method  to  an  instance  compo‐
2185       nent...Snit wouldn't know which instance should receive it.
2186
2187   HOW CAN I DELEGATE AN OPTION TO A COMPONENT OBJECT?
2188       The  first  question  in this section (see DELEGATION) shows one way to
2189       delegate an option to a component; but this pattern occurs often enough
2190       that  Snit makes it easy.  For example, every tail object has a -length
2191       option; we want to allow the creator of a dog object to set the  tail's
2192       length.  We can do this:
2193
2194              % snit::type dog {
2195                  delegate option -length to mytail
2196
2197                  constructor {args} {
2198                      install mytail using tail %AUTO% -partof $self
2199                      $self configurelist $args
2200                  }
2201              }
2202              ::dog
2203              % snit::type tail {
2204                  option -partof
2205                  option -length 5
2206              }
2207              ::tail
2208              % dog spot -length 7
2209              ::spot
2210              % spot cget -length
2211              7
2212
2213
2214       This produces nearly the same result as the -configuremethod and -cget‐
2215       method shown under the first question in this section: whenever  a  dog
2216       object's  -length  option  is  set  or  retrieved,  the underlying tail
2217       object's option is set or retrieved in turn.
2218
2219       Note that you can define an option name using the option statement,  or
2220       you can define it using delegate; you can't do both.
2221
2222   CAN I DELEGATE TO AN OPTION WITH A DIFFERENT NAME?
2223       In  the  previous  answer we delegated the dog's -length option down to
2224       its tail.  This is, of course, wrong.  The dog has a  length,  and  the
2225       tail has a length, and they are different.  What we'd really like to do
2226       is give the dog a -taillength option, but delegate  it  to  the  tail's
2227       -length option:
2228
2229              snit::type dog {
2230                  delegate option -taillength to mytail as -length
2231
2232                  constructor {args} {
2233                      set mytail [tail %AUTO% -partof $self]
2234                      $self configurelist $args
2235                  }
2236              }
2237
2238
2239   HOW CAN I DELEGATE ANY UNRECOGNIZED METHOD OR OPTION TO A COMPONENT OBJECT?
2240       It  may happen that a Snit object gets most of its behavior from one of
2241       its components.  This  often  happens  with  snit::widgetadaptors,  for
2242       example, where we wish to slightly the modify the behavior of an exist‐
2243       ing widget.  To carry on with our dog example, however, suppose that we
2244       have  a  snit::type  called  animal that implements a variety of animal
2245       behaviors--moving, eating, sleeping, and so forth.   We  want  our  dog
2246       objects  to  inherit these same behaviors, while adding dog-like behav‐
2247       iors of its own.  Here's how we can give a dog methods and  options  of
2248       its  own  while  delegating all other methods and options to its animal
2249       component:
2250
2251              snit::type dog {
2252                  delegate option * to animal
2253                  delegate method * to animal
2254
2255                  option -akc 0
2256
2257                  constructor {args} {
2258                      install animal using animal %AUTO% -name $self
2259                      $self configurelist $args
2260                  }
2261
2262                  method wag {} {
2263                      return "$self wags its tail"
2264                  }
2265              }
2266
2267
2268       That's it.  A dog is now an animal that has a -akc option and  can  wag
2269       its tail.
2270
2271       Note  that  we  don't  need to specify the full list of method names or
2272       option names that animal will receive.  It gets  anything  dog  doesn't
2273       recognize--and  if it doesn't recognize it either, it will simply throw
2274       an error, just as it should.
2275
2276       You can also delegate all unknown type  methods  to  a  type  component
2277       using delegate typemethod *.
2278
2279   HOW CAN I DELEGATE ALL BUT CERTAIN METHODS OR OPTIONS TO A COMPONENT?
2280       In the previous answer, we said that every dog is an animal by delegat‐
2281       ing all unknown methods and options to the animal component.  But  what
2282       if  the  animal type has some methods or options that we'd like to sup‐
2283       press?
2284
2285       One solution is to explicitly delegate all the options and methods, and
2286       forgo  the convenience of delegate method * and delegate option *.  But
2287       if we wish to suppress only a few options or methods, there's an easier
2288       way:
2289
2290              snit::type dog {
2291                  delegate option * to animal except -numlegs
2292                  delegate method * to animal except {fly climb}
2293
2294                  # ...
2295
2296                  constructor {args} {
2297                      install animal using animal %AUTO% -name $self -numlegs 4
2298                      $self configurelist $args
2299                  }
2300
2301                  # ...
2302              }
2303
2304
2305       Dogs  have  four legs, so we specify that explicitly when we create the
2306       animal component, and explicitly exclude -numlegs from the set of dele‐
2307       gated  options.   Similarly,  dogs  can  neither  fly  nor climb, so we
2308       exclude those animal methods as shown.
2309
2310   CAN A HIERARCHICAL METHOD BE DELEGATED?
2311       Yes; just specify multiple words in the delegated method's name:
2312
2313              snit::type tail {
2314                  method wag {} {return "Wag, wag"}
2315                  method droop {} {return "Droop, droop"}
2316              }
2317
2318              snit::type dog {
2319                  delegate method {tail wag} to mytail
2320                  delegate method {tail droop} to mytail
2321
2322                  # ...
2323
2324                  constructor {args} {
2325                      install mytail using tail %AUTO%
2326                      $self configurelist $args
2327                  }
2328
2329                  # ...
2330              }
2331
2332
2333       Unrecognized hierarchical methods can also be delegated; the  following
2334       code  delegates  all  subcommands  of the "tail" method to the "mytail"
2335       component:
2336
2337              snit::type dog {
2338                  delegate method {tail *} to mytail
2339
2340                  # ...
2341              }
2342
2343

WIDGETS

2345   WHAT IS A SNIT::WIDGET?
2346       A snit::widget is the Snit version of what Tcl programmers usually call
2347       a megawidget: a widget-like object usually consisting of one or more Tk
2348       widgets all contained within a Tk frame.
2349
2350       A snit::widget is also a special kind of snit::type.  Just about every‐
2351       thing  in  this  FAQ  list  that relates to snit::types also applies to
2352       snit::widgets.
2353
2354   HOW DO I DEFINE A SNIT::WIDGET?
2355       snit::widgets are defined  using  the  snit::widget  command,  just  as
2356       snit::types are defined by the snit::type command.
2357
2358       The  body of the definition can contain all of the same kinds of state‐
2359       ments, plus a couple of others which will be mentioned below.
2360
2361   HOW DO SNIT::WIDGETS DIFFER FROM SNIT::TYPES?
2362       ·      The name of an instance of a snit::type can  be  any  valid  Tcl
2363              command  name,  in  any namespace.  The name of an instance of a
2364              snit::widget must be a valid Tk widget name, and its parent wid‐
2365              get must already exist.
2366
2367       ·      An  instance  of  a  snit::type  can be destroyed by calling its
2368              destroy method.  Instances of a  snit::widget  have  no  destroy
2369              method; use the Tk destroy command instead.
2370
2371       ·      Every  instance  of  a snit::widget has one predefined component
2372              called its hull component.  The hull is usually a  Tk  frame  or
2373              toplevel  widget;  any  other  widgets  created  as  part of the
2374              snit::widget will usually be contained within the hull.
2375
2376       ·      snit::widgets can have their options receive default values from
2377              THE TK OPTION DATABASE.
2378
2379   WHAT IS A HULL COMPONENT?
2380       Snit can't create a Tk widget object; only Tk can do that.  Thus, every
2381       instance of a snit::widget must be wrapped around a genuine Tk  widget;
2382       this  Tk  widget is called the hull component.  Snit effectively piggy‐
2383       backs the behavior you define (methods, options, and so forth)  on  top
2384       of  the  hull component so that the whole thing behaves like a standard
2385       Tk widget.
2386
2387       For snit::widgets the hull component must be a Tk widget  that  defines
2388       the -class option.
2389
2390       snit::widgetadaptors differ from snit::widgets chiefly in that any kind
2391       of widget can be used as the hull component; see WIDGET ADAPTORS.
2392
2393   HOW CAN I SET THE HULL TYPE FOR A SNIT::WIDGET?
2394       A snit::widget's hull component will usually be a Tk frame widget; how‐
2395       ever,  it may be any Tk widget that defines the -class option.  You can
2396       explicitly choose the hull type you prefer by  including  the  hulltype
2397       command in the widget definition:
2398
2399              snit::widget mytoplevel {
2400                  hulltype toplevel
2401
2402                  # ...
2403              }
2404
2405
2406       If no hulltype command appears, the hull will be a frame.
2407
2408       By  default,  Snit  recognizes the following hull types: the Tk widgets
2409       frame,  labelframe,  toplevel,  and  the   Tile   widgets   ttk::frame,
2410       ttk::labelframe,  and  ttk::toplevel.   To enable the use of some other
2411       kind of widget as the hull type, you can lappend the widget command  to
2412       the  variable  snit::hulltypes  (always provided the widget defines the
2413       -class option.  For example, suppose Tk gets a new widget type called a
2414       prettyframe:
2415
2416              lappend snit::hulltypes prettyframe
2417
2418              snit::widget mywidget {
2419                  hulltype prettyframe
2420
2421                  # ...
2422              }
2423
2424
2425   HOW SHOULD I NAME WIDGETS WHICH ARE COMPONENTS OF A SNIT::WIDGET?
2426       Every  widget, whether a genuine Tk widget or a Snit megawidget, has to
2427       have a valid Tk window name.  When a snit::widget is first created, its
2428       instance  name, self, is a Tk window name; however, if the snit::widget
2429       is used as the hull component by  a  snit::widgetadaptor  its  instance
2430       name  will  be  changed  to  something  else.   For  this reason, every
2431       snit::widget method, constructor, destructor, and so  forth  is  passed
2432       another  implicit argument, win, which is the window name of the megaw‐
2433       idget.  Any children should be named using win as the root.
2434
2435       Thus, suppose you're writing a toolbar widget, a frame consisting of  a
2436       number  of  buttons  placed side-by-side.  It might look something like
2437       this:
2438
2439              snit::widget toolbar {
2440                  delegate option * to hull
2441
2442                  constructor {args} {
2443                      button $win.open -text Open -command [mymethod open]
2444                      button $win.save -text Save -command [mymethod save]
2445
2446                      # ....
2447
2448                      $self configurelist $args
2449
2450                  }
2451              }
2452
2453
2454       See also the question on renaming objects, toward the top of this file.
2455

WIDGET ADAPTORS

2457   WHAT IS A SNIT::WIDGETADAPTOR?
2458       A snit::widgetadaptor is a kind of snit::widget.  Whereas a  snit::wid‐
2459       get's  hull  is  automatically  created  and  is  always  a Tk frame, a
2460       snit::widgetadaptor can be based on  any  Tk  widget--or  on  any  Snit
2461       megawidget, or even (with luck) on megawidgets defined using some other
2462       package.
2463
2464       It's called a widget adaptor because it allows you to take an  existing
2465       widget and customize its behavior.
2466
2467   HOW DO I DEFINE A SNIT::WIDGETADAPTOR?
2468       Use  the  snit::widgetadaptor command.  The definition for a snit::wid‐
2469       getadaptor looks just like  that  for  a  snit::type  or  snit::widget,
2470       except that the constructor must create and install the hull component.
2471
2472       For  example, the following code creates a read-only text widget by the
2473       simple device of turning its insert and  delete  methods  into  no-ops.
2474       Then,  we  define  new methods, ins and del, which get delegated to the
2475       hull component as insert and delete.  Thus, we've adapted the text wid‐
2476       get  and  given  it new behavior while still leaving it fundamentally a
2477       text widget.
2478
2479              ::snit::widgetadaptor rotext {
2480
2481                  constructor {args} {
2482                      # Create the text widget; turn off its insert cursor
2483                      installhull using text -insertwidth 0
2484
2485                      # Apply any options passed at creation time.
2486                      $self configurelist $args
2487                  }
2488
2489                  # Disable the text widget's insert and delete methods, to
2490                  # make this readonly.
2491                  method insert {args} {}
2492                  method delete {args} {}
2493
2494                  # Enable ins and del as synonyms, so the program can insert and
2495                  # delete.
2496                  delegate method ins to hull as insert
2497                  delegate method del to hull as delete
2498
2499                  # Pass all other methods and options to the real text widget, so
2500                  # that the remaining behavior is as expected.
2501                  delegate method * to hull
2502                  delegate option * to hull
2503              }
2504
2505
2506       The most important part is in the  constructor.   Whereas  snit::widget
2507       creates the hull for you, snit::widgetadaptor cannot -- it doesn't know
2508       what kind of widget you want.  So the first thing the constructor  does
2509       is  create the hull component (a Tk text widget in this case), and then
2510       installs it using the installhull command.
2511
2512       Note: There is no instance command until you create one by installing a
2513       hull  component.  Any attempt to pass methods to $self prior to calling
2514       installhull will fail.
2515
2516   CAN I ADAPT A WIDGET CREATED ELSEWHERE IN THE PROGRAM?
2517       Yes.
2518
2519       At times, it can be convenient to adapt a pre-existing  widget  instead
2520       of  creating  your  own.   For example, the Bwidget PagesManager widget
2521       manages a set of frame widgets, only one of which is visible at a time.
2522       The  application  chooses  which  frame  is  visible.  All of the These
2523       frames are created by the PagesManager itself, using  its  add  method.
2524       It's convenient to adapt these frames to do what we'd like them to do.
2525
2526       In  a  case  like  this,  the  Tk  widget  will  already exist when the
2527       snit::widgetadaptor is created.  Snit provides an alternate form of the
2528       installhull command for this purpose:
2529
2530              snit::widgetadaptor pageadaptor {
2531                  constructor {args} {
2532                      # The widget already exists; just install it.
2533                      installhull $win
2534
2535                      # ...
2536                  }
2537              }
2538
2539
2540   CAN I ADAPT ANOTHER MEGAWIDGET?
2541       Maybe.  If  the other megawidget is a snit::widget or snit::widgetadap‐
2542       tor, then yes.  If it isn't then, again, maybe.  You'll have to try  it
2543       and  see.   You're  most  likely  to  have trouble with widget destruc‐
2544       tion--you have to make sure that  your  megawidget  code  receives  the
2545       <Destroy> event before the megawidget you're adapting does.
2546

THE TK OPTION DATABASE

2548   WHAT IS THE TK OPTION DATABASE?
2549       The  Tk  option  database  is a database of default option values main‐
2550       tained by Tk itself; every Tk application has one.  The concept of  the
2551       option  database  derives  from something called the X Windows resource
2552       database; however, the option database is available in every Tk  imple‐
2553       mentation, including those which do not use the X Windows system (e.g.,
2554       Microsoft Windows).
2555
2556       Full details about the Tk option database are beyond the scope of  this
2557       document; both Practical Programming in Tcl and Tk by Welch, Jones, and
2558       Hobbs, and Effective Tcl/Tk Programming  by  Harrison  and  McClennan.,
2559       have good introductions to it.
2560
2561       Snit  is  implemented  so  that  most of the time it will simply do the
2562       right thing with respect to the option database, provided that the wid‐
2563       get  developer  does the right thing by Snit.  The body of this section
2564       goes into great deal about what Snit  requires.   The  following  is  a
2565       brief statement of the requirements, for reference.
2566
2567       ·      If the widget's default widget class is not what is desired, set
2568              it explicitly using the widgetclass statement in the widget def‐
2569              inition.
2570
2571       ·      When  defining  or  delegating options, specify the resource and
2572              class names explicitly when necessary.
2573
2574       ·      Use the installhull using command to create and install the hull
2575              for snit::widgetadaptors.
2576
2577       ·      Use  the  install  command  to create and install all components
2578              which are widgets.
2579
2580       ·      Use the install command to create and install  components  which
2581              aren't  widgets if you'd like them to receive option values from
2582              the option database.
2583
2584       The interaction of Tk widgets with the option  database  is  a  complex
2585       thing;  the  interaction  of Snit with the option database is even more
2586       so, and repays attention to detail.
2587
2588   DO SNIT::TYPES USE THE TK OPTION DATABASE?
2589       No, they don't; querying the option database requires a Tk window name,
2590       and snit::types don't have one.
2591
2592       If  you  create  an  instance  of  a  snit::type  as  a  component of a
2593       snit::widget or snit::widgetadaptor, on the  other  hand,  and  if  any
2594       options  are delegated to the component, and if you use install to cre‐
2595       ate and install it, then the megawidget will query the option  database
2596       on  the snit::type's behalf.  This might or might not be what you want,
2597       so take care.
2598
2599   WHAT IS MY SNIT::WIDGET'S WIDGET CLASS?
2600       Every Tk widget has a "widget class": a name that is used  when  adding
2601       option  settings  to the database.  For Tk widgets, the widget class is
2602       the same as the widget command name with an initial capital.  For exam‐
2603       ple, the widget class of the Tk button widget is Button.
2604
2605       Similarly,  the widget class of a snit::widget defaults to the unquali‐
2606       fied type name with the first letter  capitalized.   For  example,  the
2607       widget class of
2608
2609              snit::widget ::mylibrary::scrolledText { ... }
2610
2611
2612       is ScrolledText.
2613
2614       The  widget  class  can  also  be  set explicitly using the widgetclass
2615       statement within the snit::widget definition:
2616
2617              snit::widget ::mylibrary::scrolledText {
2618                  widgetclass Text
2619
2620                  # ...
2621              }
2622
2623
2624       The above definition says that a scrolledText megawidget has  the  same
2625       widget  class as an ordinary text widget.  This might or might not be a
2626       good idea, depending on how the rest of the megawidget is defined,  and
2627       how its options are delegated.
2628
2629   WHAT IS MY SNIT::WIDGETADAPTOR'S WIDGET CLASS?
2630       The  widget  class of a snit::widgetadaptor is just the widget class of
2631       its hull widget; Snit has no control over this.
2632
2633       Note that the widget class can be changed only for frame  and  toplevel
2634       widgets, which is why these are the valid hull types for snit::widgets.
2635
2636       Try  to  use  snit::widgetadaptors  only to make small modifications to
2637       another widget's behavior.  Then, it will usually  not  make  sense  to
2638       change the widget's widget class anyway.
2639
2640   WHAT ARE OPTION RESOURCE AND CLASS NAMES?
2641       Every  Tk  widget option has three names: the option name, the resource
2642       name, and the class name.  The option name begins with a hyphen and  is
2643       all  lowercase; it's used when creating widgets, and with the configure
2644       and cget commands.
2645
2646       The resource and class names are used to initialize option default val‐
2647       ues by querying the option database.  The resource name is usually just
2648       the option name minus the hyphen, but may contain uppercase letters  at
2649       word  boundaries; the class name is usually just the resource name with
2650       an initial capital, but not always.  For example, here are the  option,
2651       resource, and class names for several Tk text widget options:
2652
2653                  -background         background         Background
2654                  -borderwidth        borderWidth        BorderWidth
2655                  -insertborderwidth  insertBorderWidth  BorderWidth
2656                  -padx               padX               Pad
2657
2658
2659       As  is  easily  seen,  sometimes  the  resource  and class names can be
2660       inferred from the option name, but not always.
2661
2662   WHAT ARE THE RESOURCE AND CLASS NAMES FOR MY MEGAWIDGET'S OPTIONS?
2663       For options implicitly delegated to a component using  delegate  option
2664       *,  the  resource  and class names will be exactly those defined by the
2665       component.  The configure method returns these names,  along  with  the
2666       option's default and current values:
2667
2668              % snit::widget mytext {
2669                  delegate option * to text
2670
2671                  constructor {args} {
2672                      install text using text .text
2673                      # ...
2674                  }
2675
2676                  # ...
2677              }
2678              ::mytext
2679              % mytext .text
2680              .text
2681              % .text configure -padx
2682              -padx padX Pad 1 1
2683              %
2684
2685
2686       For  all  other  options  (whether  locally defined or explicitly dele‐
2687       gated), the resource and class names can be defined explicitly, or they
2688       can be allowed to have default values.
2689
2690       By default, the resource name is just the option name minus the hyphen;
2691       the the class name is just the option name with an initial capital let‐
2692       ter.  For example, suppose we explicitly delegate "-padx":
2693
2694              % snit::widget mytext {
2695                  option -myvalue 5
2696
2697                  delegate option -padx to text
2698                  delegate option * to text
2699
2700                  constructor {args} {
2701                      install text using text .text
2702                      # ...
2703                  }
2704
2705                  # ...
2706              }
2707              ::mytext
2708              % mytext .text
2709              .text
2710              % .text configure -myvalue
2711              -myvalue myvalue Myvalue 5 5
2712              % .text configure -padx
2713              -padx padx Padx 1 1
2714              %
2715
2716
2717       Here  the  resource and class names are chosen using the default rules.
2718       Often these rules are sufficient, but in the case of "-padx" we'd  most
2719       likely  prefer  that the option's resource and class names are the same
2720       as for the built-in Tk widgets.  This is easily done:
2721
2722              % snit::widget mytext {
2723                  delegate option {-padx padX Pad} to text
2724
2725                  # ...
2726              }
2727              ::mytext
2728              % mytext .text
2729              .text
2730              % .text configure -padx
2731              -padx padX Pad 1 1
2732              %
2733
2734
2735   HOW DOES SNIT INITIALIZE MY MEGAWIDGET'S LOCALLY-DEFINED OPTIONS?
2736       The option database is queried for each of  the  megawidget's  locally-
2737       defined  options,  using  the option's resource and class name.  If the
2738       result isn't "", then it replaces the default  value  given  in  widget
2739       definition.  In either case, the default can be overridden by the call‐
2740       er.  For example,
2741
2742              option add *Mywidget.texture pebbled
2743
2744              snit::widget mywidget {
2745                  option -texture smooth
2746                  # ...
2747              }
2748
2749              mywidget .mywidget -texture greasy
2750
2751
2752       Here, -texture would normally default to "smooth", but because  of  the
2753       entry  added to the option database it defaults to "pebbled".  However,
2754       the caller has explicitly overridden the default, and so the new widget
2755       will be "greasy".
2756
2757   HOW DOES SNIT INITIALIZE DELEGATED OPTIONS?
2758       That  depends  on  whether the options are delegated to the hull, or to
2759       some other component.
2760
2761   HOW DOES SNIT INITIALIZE OPTIONS DELEGATED TO THE HULL?
2762       A snit::widget's hull is a widget, and given that its  class  has  been
2763       set  it  is expected to query the option database for itself.  The only
2764       exception concerns options that are delegated to it  with  a  different
2765       name.  Consider the following code:
2766
2767              option add *Mywidget.borderWidth 5
2768              option add *Mywidget.relief sunken
2769              option add *Mywidget.hullbackground red
2770              option add *Mywidget.background green
2771
2772              snit::widget mywidget {
2773                  delegate option -borderwidth to hull
2774                  delegate option -hullbackground to hull as -background
2775                  delegate option * to hull
2776                  # ...
2777              }
2778
2779              mywidget .mywidget
2780
2781              set A [.mywidget cget -relief]
2782              set B [.mywidget cget -hullbackground]
2783              set C [.mywidget cget -background]
2784              set D [.mywidget cget -borderwidth]
2785
2786
2787       The question is, what are the values of variables A, B, C and D?
2788
2789       The  value  of  A  is  "sunken".  The hull is a Tk frame which has been
2790       given the widget class Mywidget; it will automatically query the option
2791       database  and  pick up this value.  Since the -relief option is implic‐
2792       itly delegated to the hull, Snit takes no action.
2793
2794       The value of B is "red".  The hull will automatically pick up the value
2795       "green"  for  its  -background option, just as it picked up the -relief
2796       value.  However, Snit knows  that  -hullbackground  is  mapped  to  the
2797       hull's  -background  option;  hence, it queries the option database for
2798       -hullbackground and gets "red" and updates the hull accordingly.
2799
2800       The value of C is also "red", because -background is  implicitly  dele‐
2801       gated to the hull; thus, retrieving it is the same as retrieving -hull‐
2802       background.  Note that this case is  unusual;  the  -background  option
2803       should  probably  have  been  excluded  using  the delegate statement's
2804       except clause, or (more likely) delegated to some other component.
2805
2806       The value of D is "5", but not for the reason you think.  Note that  as
2807       it  is  defined  above,  the resource name for -borderwidth defaults to
2808       borderwidth, whereas the  option  database  entry  is  borderWidth,  in
2809       accordance  with  the  standard  Tk  naming  for  this option.  As with
2810       -relief, the hull picks up its own -borderwidth option before Snit does
2811       anything.   Because  the  option  is delegated under its own name, Snit
2812       assumes that the correct thing has happened, and doesn't worry about it
2813       any  further.   To avoid confusion, the -borderwidth option should have
2814       been delegated like this:
2815
2816                  delegate option {-borderwidth borderWidth BorderWidth} to hull
2817
2818
2819       For snit::widgetadaptors, the case is somewhat altered.   Widget  adap‐
2820       tors retain the widget class of their hull, and the hull is not created
2821       automatically by Snit.   Instead,  the  snit::widgetadaptor  must  call
2822       installhull  in  its constructor.  The normal way to do this is as fol‐
2823       lows:
2824
2825              snit::widgetadaptor mywidget {
2826                  # ...
2827                  constructor {args} {
2828                      # ...
2829                      installhull using text -foreground white
2830                      # ...
2831                  }
2832                  # ...
2833              }
2834
2835
2836       In this case, the installhull command will create the hull using a com‐
2837       mand like this:
2838
2839                  set hull [text $win -foreground white]
2840
2841
2842       The  hull  is a text widget, so its widget class is Text.  Just as with
2843       snit::widget hulls, Snit assumes that it will pick up all of its normal
2844       option values automatically, without help from Snit.  Options delegated
2845       from a different name are initialized from the option database  in  the
2846       same way as described above.
2847
2848       In earlier versions of Snit, snit::widgetadaptors were expected to call
2849       installhull like this:
2850
2851                  installhull [text $win -foreground white]
2852
2853
2854       This form still works--but Snit will not query the option  database  as
2855       described above.
2856
2857   HOW DOES SNIT INITIALIZE OPTIONS DELEGATED TO OTHER COMPONENTS?
2858       For  hull  components,  Snit  assumes  that Tk will do most of the work
2859       automatically.  Non-hull  components  are  somewhat  more  complicated,
2860       because they are matched against the option database twice.
2861
2862       A component widget remains a widget still, and is therefore initialized
2863       from the option database in the usual way.  A  text  widget  remains  a
2864       text  widget whether it is a component of a megawidget or not, and will
2865       be created as such.
2866
2867       But then, the option database is queried for all options  delegated  to
2868       the  component,  and the component is initialized accordingly--provided
2869       that the install command is used to create it.
2870
2871       Before option database support was added to Snit, the usual way to cre‐
2872       ate  a  component was to simply create it in the constructor and assign
2873       its command name to the component variable:
2874
2875              snit::widget mywidget {
2876                  delegate option -background to myComp
2877
2878                  constructor {args} {
2879                      set myComp [text $win.text -foreground black]
2880                  }
2881              }
2882
2883
2884       The drawback of this method is that Snit has no opportunity to initial‐
2885       ize the component properly.  Hence, the following approach is now used:
2886
2887              snit::widget mywidget {
2888                  delegate option -background to myComp
2889
2890                  constructor {args} {
2891                      install myComp using text $win.text -foreground black
2892                  }
2893              }
2894
2895
2896       The install command does the following:
2897
2898       ·      Builds  a list of the options explicitly included in the install
2899              command--in this case, -foreground.
2900
2901       ·      Queries the option database for all options delegated explicitly
2902              to the named component.
2903
2904       ·      Creates the component using the specified command, after insert‐
2905              ing into it a list of options and values read  from  the  option
2906              database.   Thus,  the  explicitly included options (like -fore‐
2907              ground) will override anything read from the option database.
2908
2909       ·      If the widget definition implicitly  delegated  options  to  the
2910              component  using  delegate  option  *, then Snit calls the newly
2911              created component's configure method to receive a list of all of
2912              the  component's  options.   From  this  Snit  builds  a list of
2913              options implicitly delegated to the  component  which  were  not
2914              explicitly  included  in  the  install  command.   For  all such
2915              options, Snit queries the option  database  and  configures  the
2916              component accordingly.
2917
2918       You  don't really need to know all of this; just use install to install
2919       your components, and Snit will try to do the right thing.
2920
2921   WHAT HAPPENS IF I INSTALL A NON-WIDGET AS A COMPONENT OF WIDGET?
2922       A snit::type never queries the option database.  However, a  snit::wid‐
2923       get  can  have  non-widget components.  And if options are delegated to
2924       those components, and if the install command is used to  install  those
2925       components, then they will be initialized from the option database just
2926       as widget components are.
2927
2928       However, when used within a megawidget, install assumes that  the  cre‐
2929       ated  component uses a reasonably standard widget-like creation syntax.
2930       If it doesn't, don't use install.
2931

ENSEMBLE COMMANDS

2933   WHAT IS AN ENSEMBLE COMMAND?
2934       An ensemble command is a command with subcommands.   Snit  objects  are
2935       all  ensemble  commands;  however, the term more usually refers to com‐
2936       mands like the standard Tcl commands string, file,  and  clock.   In  a
2937       sense, these are singleton objects--there's only one instance of them.
2938
2939   HOW CAN I CREATE AN ENSEMBLE COMMAND USING SNIT?
2940       There are two ways--as a snit::type, or as an instance of a snit::type.
2941
2942   HOW CAN I CREATE AN ENSEMBLE COMMAND USING AN INSTANCE OF A SNIT::TYPE?
2943       Define a type whose INSTANCE METHODS are the subcommands of your ensem‐
2944       ble command.  Then, create an instance of the  type  with  the  desired
2945       name.
2946
2947       For  example, the following code uses DELEGATION to create a work-alike
2948       for the standard string command:
2949
2950              snit::type ::mynamespace::mystringtype {
2951                  delegate method * to stringhandler
2952
2953                  constructor {} {
2954                      set stringhandler string
2955                  }
2956              }
2957
2958              ::mynamespace::mystringtype mystring
2959
2960       We create the type in a namespace, so that the type command is  hidden;
2961       then  we  create a single instance with the desired name-- mystring, in
2962       this case.
2963
2964       This method has two drawbacks.   First,  it  leaves  the  type  command
2965       floating  about.   More seriously, your shiny new ensemble command will
2966       have info and destroy subcommands that you probably have  no  use  for.
2967       But read on.
2968
2969   HOW CAN I CREATE AN ENSEMBLE COMMAND USING A SNIT::TYPE?
2970       Define  a  type whose TYPE METHODS are the subcommands of your ensemble
2971       command.
2972
2973       For example, the following code uses DELEGATION to create a  work-alike
2974       for the standard string command:
2975
2976              snit::type mystring {
2977                  delegate typemethod * to stringhandler
2978
2979                  typeconstructor {
2980                      set stringhandler string
2981                  }
2982              }
2983
2984       Now the type command itself is your ensemble command.
2985
2986       This  method  has  only  one drawback, and though it's major, it's also
2987       surmountable.  Your new ensemble command will  have  create,  info  and
2988       destroy  subcommands  you  don't want.  And worse yet, since the create
2989       method can be implicit, users of your command will accidentally be cre‐
2990       ating instances of your mystring type if they should mispell one of the
2991       subcommands.  The command will succeed--the first  time--but  won't  do
2992       what's wanted.  This is very bad.
2993
2994       The work around is to set some PRAGMAS, as shown here:
2995
2996              snit::type mystring {
2997                  pragma -hastypeinfo    no
2998                  pragma -hastypedestroy no
2999                  pragma -hasinstances   no
3000
3001                  delegate typemethod * to stringhandler
3002
3003                  typeconstructor {
3004                      set stringhandler string
3005                  }
3006              }
3007
3008       Here  we've  used  the pragma statement to tell Snit that we don't want
3009       the info typemethod or the destroy typemethod, and that our type has no
3010       instances;  this eliminates the create typemethod and all related code.
3011       As a result, our ensemble command will be well-behaved, with  no  unex‐
3012       pected subcommands.
3013

PRAGMAS

3015   WHAT IS A PRAGMA?
3016       A pragma is an option you can set in your type definitions that affects
3017       how the type is defined and how it works once it is defined.
3018
3019   HOW DO I SET A PRAGMA?
3020       Use the pragma statement.  Each pragma is an option with a value;  each
3021       time you use the pragma statement you can set one or more of them.
3022
3023   HOW CAN I GET RID OF THE  INFO" TYPE METHOD?"
3024       Set the -hastypeinfo pragma to no:
3025
3026              snit::type dog {
3027                  pragma -hastypeinfo no
3028                  # ...
3029              }
3030
3031       Snit will refrain from defining the info type method.
3032
3033   HOW CAN I GET RID OF THE  DESTROY" TYPE METHOD?"
3034       Set the -hastypedestroy pragma to no:
3035
3036              snit::type dog {
3037                  pragma -hastypedestroy no
3038                  # ...
3039              }
3040
3041       Snit will refrain from defining the destroy type method.
3042
3043   HOW CAN I GET RID OF THE  CREATE" TYPE METHOD?"
3044       Set the -hasinstances pragma to no:
3045
3046              snit::type dog {
3047                  pragma -hasinstances no
3048                  # ...
3049              }
3050
3051       Snit will refrain from defining the create type method; if you call the
3052       type command with an unknown method name, you'll get an  error  instead
3053       of a new instance of the type.
3054
3055       This  is  useful  if you wish to use a snit::type to define an ensemble
3056       command rather than a type with instances.
3057
3058       Pragmas -hastypemethods and -hasinstances  cannot  both  be  false  (or
3059       there'd be nothing left).
3060
3061   HOW CAN I GET RID OF TYPE METHODS ALTOGETHER?
3062       Normal  Tk  widget type commands don't have subcommands; all they do is
3063       create widgets--in Snit terms, the type command calls the  create  type
3064       method  directly.   To  get  the  same  behavior  from  Snit,  set  the
3065       -hastypemethods pragma to no:
3066
3067              snit::type dog {
3068                  pragma -hastypemethods no
3069                  #...
3070              }
3071
3072              # Creates ::spot
3073              dog spot
3074
3075              # Tries to create an instance called ::create
3076              dog create spot
3077
3078       Pragmas -hastypemethods and -hasinstances  cannot  both  be  false  (or
3079       there'd be nothing left).
3080
3081   WHY  CAN'T  I  CREATE  AN  OBJECT THAT REPLACES AN OLD OBJECT WITH THE SAME
3082       NAME?
3083       Up until Snit 0.95, you could  use  any  name  for  an  instance  of  a
3084       snit::type, even if the name was already in use by some other object or
3085       command.  You could do the following, for example:
3086
3087              snit::type dog { ... }
3088
3089              dog proc
3090
3091       You now have a new dog named "proc", which is  probably  not  something
3092       that you really wanted to do.  As a result, Snit now throws an error if
3093       your chosen instance name names an existing command.   To  restore  the
3094       old behavior, set the -canreplace pragma to yes:
3095
3096              snit::type dog {
3097                  pragma -canreplace yes
3098                  # ...
3099              }
3100
3101
3102   HOW CAN I MAKE MY SIMPLE TYPE RUN FASTER?
3103       In Snit 1.x, you can set the -simpledispatch pragma to yes.
3104
3105       Snit 1.x method dispatch is both flexible and fast, but the flexibility
3106       comes with a price.  If your type doesn't require the flexibility,  the
3107       -simpledispatch  pragma  allows  you  to  substitute a simpler dispatch
3108       mechanism that runs quite a bit faster.  The limitations are these:
3109
3110       ·      Methods cannot be delegated.
3111
3112       ·      uplevel and upvar do not work as expected: the caller's scope is
3113              two levels up rather than one.
3114
3115       ·      The option-handling methods (cget, configure, and configurelist)
3116              are very slightly slower.
3117
3118       In Snit 2.2, the -simpledispatch macro is obsolete,  and  ignored;  all
3119       Snit 2.2 method dispatch is faster than Snit 1.x's -simpledispatch.
3120

MACROS

3122   WHAT IS A MACRO?
3123       A  Snit macro is nothing more than a Tcl proc that's defined in the Tcl
3124       interpreter used to compile Snit type definitions.
3125
3126   WHAT ARE MACROS GOOD FOR?
3127       You can use Snit macros to define new type definition  syntax,  and  to
3128       support conditional compilation.
3129
3130   HOW DO I DO CONDITIONAL COMPILATION?
3131       Suppose you want your type to use a fast C extension if it's available;
3132       otherwise, you'll fallback to a slower Tcl implementation.  You want to
3133       define  one  set  of  methods in the first case, and another set in the
3134       second case.  But how can your type definition know whether the fast  C
3135       extension is available or not?
3136
3137       It's  easily done.  Outside of any type definition, define a macro that
3138       returns 1 if the extension is available, and 0 otherwise:
3139
3140              if {$gotFastExtension} {
3141                  snit::macro fastcode {} {return 1}
3142              } else {
3143                  snit::macro fastcode {} {return 0}
3144              }
3145
3146       Then, use your macro in your type definition:
3147
3148              snit::type dog {
3149
3150                  if {[fastcode]} {
3151                      # Fast methods
3152                      method bark {} {...}
3153                      method wagtail {} {...}
3154                  } else {
3155                      # Slow methods
3156                      method bark {} {...}
3157                      method wagtail {} {...}
3158                  }
3159              }
3160
3161
3162   HOW DO I DEFINE NEW TYPE DEFINITION SYNTAX?
3163       Use a macro.   For  example,  your  snit::widget's  -background  option
3164       should  be  propagated  to  a  number  of component widgets.  You could
3165       implement that like this:
3166
3167              snit::widget mywidget {
3168                  option -background -default white -configuremethod PropagateBackground
3169
3170                  method PropagateBackground {option value} {
3171                      $comp1 configure $option $value
3172                      $comp2 configure $option $value
3173                      $comp3 configure $option $value
3174                  }
3175              }
3176
3177       For one option, this is fine; if you've got a  number  of  options,  it
3178       becomes tedious and error prone.  So package it as a macro:
3179
3180              snit::macro propagate {option "to" components} {
3181                  option $option -configuremethod Propagate$option
3182
3183                  set body "\n"
3184
3185                  foreach comp $components {
3186                      append body "\$$comp configure $option \$value\n"
3187                  }
3188
3189                  method Propagate$option {option value} $body
3190              }
3191
3192       Then you can use it like this:
3193
3194              snit::widget mywidget {
3195                  option -background default -white
3196                  option -foreground default -black
3197
3198                  propagate -background to {comp1 comp2 comp3}
3199                  propagate -foreground to {comp1 comp2 comp3}
3200              }
3201
3202
3203   ARE THERE ARE RESTRICTIONS ON MACRO NAMES?
3204       Yes,  there  are.  You can't redefine any standard Tcl commands or Snit
3205       type definition statements.   You  can  use  any  other  command  name,
3206       including the name of a previously defined macro.
3207
3208       If you're using Snit macros in your application, go ahead and name them
3209       in the global namespace, as shown above.  But if you're using  them  to
3210       define  types  or  widgets  for  use  by others, you should define your
3211       macros in the same namespace as your types or widgets.  That way,  they
3212       won't conflict with other people's macros.
3213
3214       If my fancy snit::widget is called ::mylib::mywidget, for example, then
3215       I should define my propagate macro as ::mylib::propagate:
3216
3217              snit::macro mylib::propagate {option "to" components} { ... }
3218
3219              snit::widget ::mylib::mywidget {
3220                  option -background default -white
3221                  option -foreground default -black
3222
3223                  mylib::propagate -background to {comp1 comp2 comp3}
3224                  mylib::propagate -foreground to {comp1 comp2 comp3}
3225              }
3226
3227

BUGS, IDEAS, FEEDBACK

3229       This document, and the package it describes, will  undoubtedly  contain
3230       bugs  and  other  problems.  Please report such in the category snit of
3231       the  Tcllib  Trackers  [http://core.tcl.tk/tcllib/reportlist].   Please
3232       also  report any ideas for enhancements you may have for either package
3233       and/or documentation.
3234
3235       When proposing code changes, please provide unified diffs, i.e the out‐
3236       put of diff -u.
3237
3238       Note  further  that  attachments  are  strongly  preferred over inlined
3239       patches. Attachments can be made by going  to  the  Edit  form  of  the
3240       ticket  immediately  after  its  creation, and then using the left-most
3241       button in the secondary navigation bar.
3242

KEYWORDS

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

CATEGORY

3248       Programming tools
3249
3251       Copyright (c) 2003-2006, by William H. Duquette
3252
3253
3254
3255
3256tcllib                                2.2                           snitfaq(n)
Impressum