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.1 requires Tcl 8.3 or later; Snit 2.1 requires Tcl 8.5 or later.
52       See SNIT VERSIONS for the differences between Snit 1.1 and Snit 2.1.
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 should be at least as efficient as a  hand-
61              coded        Tcl        object       (see       http://www.wjdu
62              quette.com/tcl/objects.html).
63
64       ·      The fact that Snit was used in an object's implementation should
65              be transparent (and irrelevant) to clients of that object.
66
67       ·      Snit  should  be able to encapsulate objects from other sources,
68              particularly Tk widgets.
69
70       ·      Snit megawidgets should be (to the  extent  possible)  indistin‐
71              guishable in interface from Tk widgets.
72
73       ·      Snit  should  be  Tclish--that is, rather than trying to emulate
74              C++, Smalltalk, or anything else, it should try to  emulate  Tcl
75              itself.
76
77       ·      It should have a simple, easy-to-use, easy-to-remember syntax.
78
79   How is Snit different from other OO frameworks?
80       Snit  is  unique  among  Tcl  object systems in that it is based not on
81       inheritance but on delegation.  Object  systems  based  on  inheritance
82       only  allow  you to inherit from classes defined using the same system,
83       and that's a shame.  In Tcl, an object is anything that  acts  like  an
84       object; it shouldn't matter how the object was implemented.  I designed
85       Snit to help me build applications out of the materials at hand;  thus,
86       Snit  is  designed  to  be able to incorporate and build on any object,
87       whether it's a hand-coded object, a Tk widget, an Incr  Tcl  object,  a
88       BWidget or almost anything else.
89
90       Note  that  you  can achieve the effect of inheritance using COMPONENTS
91       and DELEGATION--and you can inherit from anything that looks like a Tcl
92       object.
93
94   What can I do with Snit?
95       Using Snit, a programmer can:
96
97       ·      Create abstract data types and Tk megawidgets.
98
99       ·      Define instance variables, type variables, and Tk-style options.
100
101       ·      Define  constructors,  destructors, instance methods, type meth‐
102              ods, procs.
103
104       ·      Assemble a type out of component types.   Instance  methods  and
105              options can be delegated to the component types automatically.
106

SNIT VERSIONS

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

OBJECTS

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

INSTANCE METHODS

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

INSTANCE VARIABLES

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

OPTIONS

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

TYPE VARIABLES

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

TYPE METHODS

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

PROCS

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

TYPE CONSTRUCTORS

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

CONSTRUCTORS

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

DESTRUCTORS

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

COMPONENTS

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

TYPE COMPONENTS

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

DELEGATION

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

WIDGETS

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

WIDGET ADAPTORS

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

THE TK OPTION DATABASE

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

ENSEMBLE COMMANDS

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

PRAGMAS

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

MACROS

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

KEYWORDS

3178       BWidget, C++, Incr Tcl, adaptors, class, mega  widget,  object,  object
3179       oriented, widget, widget adaptors
3180
3182       Copyright (c) 2003-2006, by William H. Duquette
3183
3184
3185
3186
3187snit                                  2.1                           snitfaq(n)
Impressum