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 ap‐
28       plication.
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 ap‐
33       plication.
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  in‐
80       heritance  but on delegation.  Object systems based on inheritance only
81       allow you to inherit from classes defined using the  same  system,  and
82       that's  a  shame.   In Tcl, an object is anything that acts like an ob‐
83       ject; 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 re‐
116       quires 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  in‐
132       stead:
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  in‐
151       evitable  because Snit 2.2 uses Tcl 8.5's new namespace ensemble mecha‐
152       nism 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  de‐
161              fine  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  en‐
170              semble mechanism; and namespace ensemble doesn't allow an ensem‐
171              ble command to be called without a subcommand.  In short,  using
172              namespace ensemble there's no way to support implicit naming.
173
174              All is not lost, however.  If the type has no type methods, then
175              the type command is a simple command rather  than  an  ensemble,
176              and namespace ensemble is not used.  In this case, implicit nam‐
177              ing is still possible.
178
179              In short, you can have implicit naming if you're willing  to  do
180              without  type methods (including the standard type methods, like
181              $type info).  To do so, use the -hastypemethods pragma:
182
183              pragma -hastypemethods 0
184
185       •      Hierarchical methods and type methods  are  implemented  differ‐
186              ently in Snit 2.2.
187
188              A  hierarchical  method  is an instance method which has subcom‐
189              mands; these subcommands are themselves methods.   The  Tk  text
190              widget's tag command and its subcommands are examples of hierar‐
191              chical methods.  You can implement such subcommands in Snit sim‐
192              ply by including multiple words in the method names:
193
194              method {tag configure} {tag args} { ... }
195
196              method {tag cget} {tag option} {...}
197
198
199              Here we've implicitly defined a tag method which has two subcom‐
200              mands, configure and cget.
201
202              In Snit 1.3, hierarchical methods could be called in two ways:
203
204              $obj tag cget -myoption      ;# The good way
205              $obj {tag cget} -myoption    ;# The weird way
206
207
208              In the second call, we see that a hierarchical  method  or  type
209              method is simply one whose name contains multiple words.
210
211              In  Snit  2.2 this is no longer the case, and the "weird" way of
212              calling hierarchical methods and type methods no longer works.
213
214       •      The third incompatibility derives from the second.  In Snit 1.3,
215              hierarchical  methods  were  also simply methods whose name con‐
216              tains multiple words.  As a result, $obj info  methods  returned
217              the  full  names  of  all  hierarchical methods.  In the example
218              above, the list returned by $obj info methods would include  tag
219              configure  and  tag  cget but not tag, since tag is defined only
220              implicitly.
221
222              In Snit 2.2, hierarchical methods and type methods are no longer
223              simply ones whose name contains multiple words; in the above ex‐
224              ample, the list returned by $obj info methods would include  tag
225              but not tag configure or tag cget.
226
227       •      The  fourth  incompatibility  is due to a new feature.  Snit 2.2
228              uses the new namespace path command so that a  type's  code  can
229              call  any command defined in the type's parent namespace without
230              qualification or importation.  For example, suppose you  have  a
231              package  called mypackage which defines a number of commands in‐
232              cluding a type, ::mypackage::mytype.  Thanks to namespace  path,
233              the  type's  code  can call any of the other commands defined in
234              ::mypackage::.
235
236              This is extremely convenient.  However, it also means that  com‐
237              mands  defined  in the parent namespace, ::mypackage:: can block
238              the type's access to identically named commands  in  the  global
239              namespace.  This can lead to bugs.  For example, Tcllib includes
240              a type called ::tie::std::file.   This  type's  code  calls  the
241              standard file command.  When run with Snit 2.2, the code broke--
242              the type's command, ::tie::std::file, is itself a command in the
243              type's  parent namespace, and so instead of calling the standard
244              file command, the type found itself calling itself.
245
246   ARE THERE OTHER DIFFERENCES BETWEEN SNIT 1.X AND SNIT 2.2?
247       Yes.
248
249       •      Method dispatch is considerably faster.
250
251       •      Many error messages and stack traces are cleaner.
252
253       •      The -simpledispatch pragma is obsolete, and ignored if  present.
254              In  Snit 1.x, -simpledispatch substitutes a faster mechanism for
255              method dispatch, at the cost of losing certain  features.   Snit
256              2.2 method dispatch is faster still in all cases, so -simpledis‐
257              patch is no longer needed.
258
259       •      In Snit 2.2, a type's code (methods,  type  methods,  etc.)  can
260              call  commands from the type's parent namespace without qualify‐
261              ing or importing them, i.e., type ::parentns::mytype's code  can
262              call ::parentns::someproc as just someproc.
263
264              This  is  extremely  useful  when a type is defined as part of a
265              larger package, and shares a parent namespace with the  rest  of
266              the  package; it means that the type can call other commands de‐
267              fined by the package without any extra work.
268
269              This feature depends on the new Tcl 8.5 namespace path  command,
270              which is why it hasn't been implemented for V1.x.  V1.x code can
271              achieve something similar by placing
272
273              namespace import [namespace parent]::*
274
275              in a type constructor.  This is  less  useful,  however,  as  it
276              picks up only those commands which have already been exported by
277              the parent namespace at the time the type is defined.
278

OBJECTS

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

INSTANCE METHODS

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

INSTANCE VARIABLES

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

OPTIONS

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

TYPE VARIABLES

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

TYPE METHODS

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

PROCS

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

TYPE CONSTRUCTORS

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

CONSTRUCTORS

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

DESTRUCTORS

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

COMPONENTS

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

TYPE COMPONENTS

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

DELEGATION

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

WIDGETS

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

WIDGET ADAPTORS

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

THE TK OPTION DATABASE

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

ENSEMBLE COMMANDS

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

PRAGMAS

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

MACROS

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

BUGS, IDEAS, FEEDBACK

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

KEYWORDS

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

CATEGORY

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