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

NAME

8       snitfaq - Snit Frequently Asked Questions
9

DESCRIPTION

OVERVIEW

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

SNIT VERSIONS

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

OBJECTS

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

INSTANCE METHODS

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

INSTANCE VARIABLES

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

OPTIONS

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

TYPE VARIABLES

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

TYPE METHODS

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

PROCS

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

TYPE CONSTRUCTORS

1492   WHAT IS A TYPE CONSTRUCTOR?
1493       A  type  constructor  is  a body of code that initializes the type as a
1494       whole, rather like a C++ static initializer.  The body of a  type  con‐
1495       structor is executed once when the type is defined, and never again.
1496
1497       A type can have at most one type constructor.
1498
1499   HOW DO I DEFINE A TYPE CONSTRUCTOR?
1500       A type constructor is defined by using the typeconstructor statement in
1501       the type definition.  For example, suppose the type uses an  array-val‐
1502       ued  type variable as a look-up table, and the values in the array have
1503       to be computed at start-up.
1504
1505       % snit::type mytype {
1506           typevariable lookupTable
1507
1508           typeconstructor {
1509               array set lookupTable {key value...}
1510           }
1511       }
1512
1513

CONSTRUCTORS

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

DESTRUCTORS

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

COMPONENTS

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

TYPE COMPONENTS

1952   WHAT IS A TYPE COMPONENT?
1953       A type component is a component that belongs to the type itself instead
1954       of to a particular instance of the type.  The relationship between com‐
1955       ponents and type components is the same  as  the  relationship  between
1956       INSTANCE  VARIABLES and TYPE VARIABLES.  Both INSTANCE METHODS and TYPE
1957       METHODS can be delegated to type components.
1958
1959       Once you understand COMPONENTS and DELEGATION, type components are just
1960       more of the same.
1961
1962   HOW DO I DECLARE A TYPE COMPONENT?
1963       Declare  a  type component using the typecomponent statement.  It takes
1964       the same options (-inherit and  -public)  as  the  component  statement
1965       does,  and  defines a type variable to hold the type component's object
1966       command.
1967
1968       Suppose in your model you've got many dogs, but only one  veterinarian.
1969       You might make the veterinarian a type component.
1970       snit::type veterinarian { ... }
1971
1972       snit::type dog {
1973           typecomponent vet
1974
1975           # ...
1976       }
1977
1978
1979   HOW DO I INSTALL A TYPE COMPONENT?
1980       Just  use  the  set command to assign the component's object command to
1981       the type component.  Because types (even snit::widget  types)  are  not
1982       widgets,  and  do  not  have  options anyway, the extra features of the
1983       install command are not needed.
1984
1985       You'll usually install type components  in  the  type  constructor,  as
1986       shown here:
1987       snit::type veterinarian { ... }
1988
1989       snit::type dog {
1990           typecomponent vet
1991
1992           typeconstructor {
1993               set vet [veterinarian %AUTO%]
1994           }
1995       }
1996
1997
1998   ARE THERE ANY LIMITATIONS ON TYPE COMPONENT NAMES?
1999       Yes, the same as on INSTANCE VARIABLES, TYPE VARIABLES, and normal COM‐
2000       PONENTS.
2001

DELEGATION

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

WIDGETS

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

WIDGET ADAPTORS

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

THE TK OPTION DATABASE

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

ENSEMBLE COMMANDS

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

PRAGMAS

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

MACROS

3083   WHAT IS A MACRO?
3084       A  Snit macro is nothing more than a Tcl proc that's defined in the Tcl
3085       interpreter used to compile Snit type definitions.
3086
3087   WHAT ARE MACROS GOOD FOR?
3088       You can use Snit macros to define new type definition  syntax,  and  to
3089       support conditional compilation.
3090
3091   HOW DO I DO CONDITIONAL COMPILATION?
3092       Suppose you want your type to use a fast C extension if it's available;
3093       otherwise, you'll fallback to a slower Tcl implementation.  You want to
3094       define  one  set  of  methods in the first case, and another set in the
3095       second case.  But how can your type definition know whether the fast  C
3096       extension is available or not?
3097
3098       It's  easily done.  Outside of any type definition, define a macro that
3099       returns 1 if the extension is available, and 0 otherwise:
3100       if {$gotFastExtension} {
3101           snit::macro fastcode {} {return 1}
3102       } else {
3103           snit::macro fastcode {} {return 0}
3104       }
3105
3106       Then, use your macro in your type definition:
3107       snit::type dog {
3108
3109           if {[fastcode]} {
3110               # Fast methods
3111               method bark {} {...}
3112               method wagtail {} {...}
3113           } else {
3114               # Slow methods
3115               method bark {} {...}
3116               method wagtail {} {...}
3117           }
3118       }
3119
3120
3121   HOW DO I DEFINE NEW TYPE DEFINITION SYNTAX?
3122       Use a macro.   For  example,  your  snit::widget's  -background  option
3123       should  be  propagated  to  a  number  of component widgets.  You could
3124       implement that like this:
3125       snit::widget mywidget {
3126           option -background -default white -configuremethod PropagateBackground
3127
3128           method PropagateBackground {option value} {
3129               $comp1 configure $option $value
3130               $comp2 configure $option $value
3131               $comp3 configure $option $value
3132           }
3133       }
3134
3135       For one option, this is fine; if you've got a  number  of  options,  it
3136       becomes tedious and error prone.  So package it as a macro:
3137       snit::macro propagate {option "to" components} {
3138           option $option -configuremethod Propagate$option
3139
3140           set body "\n"
3141
3142           foreach comp $components {
3143               append body "\$$comp configure $option \$value\n"
3144           }
3145
3146           method Propagate$option {option value} $body
3147       }
3148
3149       Then you can use it like this:
3150       snit::widget mywidget {
3151           option -background default -white
3152           option -foreground default -black
3153
3154           propagate -background to {comp1 comp2 comp3}
3155           propagate -foreground to {comp1 comp2 comp3}
3156       }
3157
3158
3159   ARE THERE ARE RESTRICTIONS ON MACRO NAMES?
3160       Yes,  there  are.  You can't redefine any standard Tcl commands or Snit
3161       type definition statements.   You  can  use  any  other  command  name,
3162       including the name of a previously defined macro.
3163
3164       If you're using Snit macros in your application, go ahead and name them
3165       in the global namespace, as shown above.  But if you're using  them  to
3166       define  types  or  widgets  for  use  by others, you should define your
3167       macros in the same namespace as your types or widgets.  That way,  they
3168       won't conflict with other people's macros.
3169
3170       If my fancy snit::widget is called ::mylib::mywidget, for example, then
3171       I should define my propagate macro as ::mylib::propagate:
3172       snit::macro mylib::propagate {option "to" components} { ... }
3173
3174       snit::widget ::mylib::mywidget {
3175           option -background default -white
3176           option -foreground default -black
3177
3178           mylib::propagate -background to {comp1 comp2 comp3}
3179           mylib::propagate -foreground to {comp1 comp2 comp3}
3180       }
3181
3182

BUGS, IDEAS, FEEDBACK

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

KEYWORDS

3191       BWidget, C++, Incr Tcl, adaptors, class, mega  widget,  object,  object
3192       oriented, widget, widget adaptors
3193
3195       Copyright (c) 2003-2006, by William H. Duquette
3196
3197
3198
3199
3200snit                                  2.2                           snitfaq(n)
Impressum