'\"
'\" Generated from file 'snit\&.man' by tcllib/doctools with format 'nroff'
'\" Copyright (c) 2003-2009, by William H\&. Duquette
'\"
.TH "snit" n 2\&.3\&.2 tcllib "Snit's Not Incr Tcl, OO system"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\"	Start paragraph describing an argument to a library procedure.
.\"	type is type of argument (int, etc.), in/out is either "in", "out",
.\"	or "in/out" to describe whether procedure reads or modifies arg,
.\"	and indent is equivalent to second arg of .IP (shouldn't ever be
.\"	needed;  use .AS below instead)
.\"
.\" .AS ?type? ?name?
.\"	Give maximum sizes of arguments for setting tab stops.  Type and
.\"	name are examples of largest possible arguments that will be passed
.\"	to .AP later.  If args are omitted, default tab stops are used.
.\"
.\" .BS
.\"	Start box enclosure.  From here until next .BE, everything will be
.\"	enclosed in one large box.
.\"
.\" .BE
.\"	End of box enclosure.
.\"
.\" .CS
.\"	Begin code excerpt.
.\"
.\" .CE
.\"	End code excerpt.
.\"
.\" .VS ?version? ?br?
.\"	Begin vertical sidebar, for use in marking newly-changed parts
.\"	of man pages.  The first argument is ignored and used for recording
.\"	the version when the .VS was added, so that the sidebars can be
.\"	found and removed when they reach a certain age.  If another argument
.\"	is present, then a line break is forced before starting the sidebar.
.\"
.\" .VE
.\"	End of vertical sidebar.
.\"
.\" .DS
.\"	Begin an indented unfilled display.
.\"
.\" .DE
.\"	End of indented unfilled display.
.\"
.\" .SO ?manpage?
.\"	Start of list of standard options for a Tk widget. The manpage
.\"	argument defines where to look up the standard options; if
.\"	omitted, defaults to "options". The options follow on successive
.\"	lines, in three columns separated by tabs.
.\"
.\" .SE
.\"	End of list of standard options for a Tk widget.
.\"
.\" .OP cmdName dbName dbClass
.\"	Start of description of a specific option.  cmdName gives the
.\"	option's name as specified in the class command, dbName gives
.\"	the option's name in the option database, and dbClass gives
.\"	the option's class in the option database.
.\"
.\" .UL arg1 arg2
.\"	Print arg1 underlined, then print arg2 normally.
.\"
.\" .QW arg1 ?arg2?
.\"	Print arg1 in quotes, then arg2 normally (for trailing punctuation).
.\"
.\" .PQ arg1 ?arg2?
.\"	Print an open parenthesis, arg1 in quotes, then arg2 normally
.\"	(for trailing punctuation) and then a closing parenthesis.
.\"
.\"	# Set up traps and other miscellaneous stuff for Tcl/Tk man pages.
.if t .wh -1.3i ^B
.nr ^l \n(.l
.ad b
.\"	# Start an argument description
.de AP
.ie !"\\$4"" .TP \\$4
.el \{\
.   ie !"\\$2"" .TP \\n()Cu
.   el          .TP 15
.\}
.ta \\n()Au \\n()Bu
.ie !"\\$3"" \{\
\&\\$1 \\fI\\$2\\fP (\\$3)
.\".b
.\}
.el \{\
.br
.ie !"\\$2"" \{\
\&\\$1	\\fI\\$2\\fP
.\}
.el \{\
\&\\fI\\$1\\fP
.\}
.\}
..
.\"	# define tabbing values for .AP
.de AS
.nr )A 10n
.if !"\\$1"" .nr )A \\w'\\$1'u+3n
.nr )B \\n()Au+15n
.\"
.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
.nr )C \\n()Bu+\\w'(in/out)'u+2n
..
.AS Tcl_Interp Tcl_CreateInterp in/out
.\"	# BS - start boxed text
.\"	# ^y = starting y location
.\"	# ^b = 1
.de BS
.br
.mk ^y
.nr ^b 1u
.if n .nf
.if n .ti 0
.if n \l'\\n(.lu\(ul'
.if n .fi
..
.\"	# BE - end boxed text (draw box now)
.de BE
.nf
.ti 0
.mk ^t
.ie n \l'\\n(^lu\(ul'
.el \{\
.\"	Draw four-sided box normally, but don't draw top of
.\"	box if the box started on an earlier page.
.ie !\\n(^b-1 \{\
\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.el \}\
\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.\}
.fi
.br
.nr ^b 0
..
.\"	# VS - start vertical sidebar
.\"	# ^Y = starting y location
.\"	# ^v = 1 (for troff;  for nroff this doesn't matter)
.de VS
.if !"\\$2"" .br
.mk ^Y
.ie n 'mc \s12\(br\s0
.el .nr ^v 1u
..
.\"	# VE - end of vertical sidebar
.de VE
.ie n 'mc
.el \{\
.ev 2
.nf
.ti 0
.mk ^t
\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
.sp -1
.fi
.ev
.\}
.nr ^v 0
..
.\"	# Special macro to handle page bottom:  finish off current
.\"	# box/sidebar if in box/sidebar mode, then invoked standard
.\"	# page bottom macro.
.de ^B
.ev 2
'ti 0
'nf
.mk ^t
.if \\n(^b \{\
.\"	Draw three-sided box if this is the box's first page,
.\"	draw two sides but no top otherwise.
.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.\}
.if \\n(^v \{\
.nr ^x \\n(^tu+1v-\\n(^Yu
\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
.\}
.bp
'fi
.ev
.if \\n(^b \{\
.mk ^y
.nr ^b 2
.\}
.if \\n(^v \{\
.mk ^Y
.\}
..
.\"	# DS - begin display
.de DS
.RS
.nf
.sp
..
.\"	# DE - end display
.de DE
.fi
.RE
.sp
..
.\"	# SO - start of list of standard options
.de SO
'ie '\\$1'' .ds So \\fBoptions\\fR
'el .ds So \\fB\\$1\\fR
.SH "STANDARD OPTIONS"
.LP
.nf
.ta 5.5c 11c
.ft B
..
.\"	# SE - end of list of standard options
.de SE
.fi
.ft R
.LP
See the \\*(So manual entry for details on the standard options.
..
.\"	# OP - start of full description for a single option
.de OP
.LP
.nf
.ta 4c
Command-Line Name:	\\fB\\$1\\fR
Database Name:	\\fB\\$2\\fR
Database Class:	\\fB\\$3\\fR
.fi
.IP
..
.\"	# CS - begin code excerpt
.de CS
.RS
.nf
.ta .25i .5i .75i 1i
..
.\"	# CE - end code excerpt
.de CE
.fi
.RE
..
.\"	# UL - underline word
.de UL
\\$1\l'|0\(ul'\\$2
..
.\"	# QW - apply quotation marks to word
.de QW
.ie '\\*(lq'"' ``\\$1''\\$2
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\$2
..
.\"	# PQ - apply parens and quotation marks to word
.de PQ
.ie '\\*(lq'"' (``\\$1''\\$2)\\$3
.\"" fix emacs highlighting
.el (\\*(lq\\$1\\*(rq\\$2)\\$3
..
.\"	# QR - quoted range
.de QR
.ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3
..
.\"	# MT - "empty" string
.de MT
.QW ""
..
.BS
.SH NAME
snit \- Snit's Not Incr Tcl
.SH SYNOPSIS
package require \fBTcl  8\&.5\fR
.sp
package require \fBsnit  ?2\&.3\&.2?\fR
.sp
\fBsnit::type\fR \fIname\fR \fIdefinition\fR
.sp
\fBtypevariable\fR \fIname\fR ?\fB-array\fR? ?\fIvalue\fR?
.sp
\fBtypemethod\fR \fIname\fR \fIarglist\fR \fIbody\fR
.sp
\fBtypeconstructor\fR \fIbody\fR
.sp
\fBvariable\fR \fIname\fR ?\fB-array\fR? ?\fIvalue\fR?
.sp
\fBmethod\fR \fIname\fR \fIarglist\fR \fIbody\fR
.sp
\fBoption\fR \fInamespec\fR ?\fIdefaultValue\fR?
.sp
\fBoption\fR \fInamespec\fR ?\fIoptions\&.\&.\&.\fR?
.sp
\fBconstructor\fR \fIarglist\fR \fIbody\fR
.sp
\fBdestructor\fR \fIbody\fR
.sp
\fBproc\fR \fIname\fR \fIargs\fR \fIbody\fR
.sp
\fBdelegate\fR \fBmethod\fR \fIname\fR \fBto\fR \fIcomp\fR ?\fBas\fR \fItarget\fR?
.sp
\fBdelegate\fR \fBmethod\fR \fIname\fR ?\fBto\fR \fIcomp\fR? \fBusing\fR \fIpattern\fR
.sp
\fBdelegate\fR \fBmethod\fR \fB*\fR ?\fBto\fR \fIcomp\fR? ?\fBusing\fR \fIpattern\fR? ?\fBexcept\fR \fIexceptions\fR?
.sp
\fBdelegate\fR \fBoption\fR \fInamespec\fR \fBto\fR \fIcomp\fR
.sp
\fBdelegate\fR \fBoption\fR \fInamespec\fR \fBto\fR \fIcomp\fR \fBas\fR \fItarget\fR
.sp
\fBdelegate\fR \fBoption\fR \fB*\fR \fBto\fR \fIcomp\fR
.sp
\fBdelegate\fR \fBoption\fR \fB*\fR \fBto\fR \fIcomp\fR \fBexcept\fR \fIexceptions\fR
.sp
\fBcomponent\fR \fIcomp\fR ?\fB-public\fR \fImethod\fR? ?\fB-inherit\fR \fIflag\fR?
.sp
\fBdelegate\fR \fBtypemethod\fR \fIname\fR \fBto\fR \fIcomp\fR ?\fBas\fR \fItarget\fR?
.sp
\fBdelegate\fR \fBtypemethod\fR \fIname\fR ?\fBto\fR \fIcomp\fR? \fBusing\fR \fIpattern\fR
.sp
\fBdelegate\fR \fBtypemethod\fR \fB*\fR ?\fBto\fR \fIcomp\fR? ?\fBusing\fR \fIpattern\fR? ?\fBexcept\fR \fIexceptions\fR?
.sp
\fBtypecomponent\fR \fIcomp\fR ?\fB-public\fR \fItypemethod\fR? ?\fB-inherit\fR \fIflag\fR?
.sp
\fBpragma\fR ?\fIoptions\&.\&.\&.\fR?
.sp
\fBexpose\fR \fIcomp\fR
.sp
\fBexpose\fR \fIcomp\fR \fBas\fR \fImethod\fR
.sp
\fBonconfigure\fR \fIname\fR \fIarglist\fR \fIbody\fR
.sp
\fBoncget\fR \fIname\fR \fIbody\fR
.sp
\fBsnit::widget\fR \fIname\fR \fIdefinition\fR
.sp
\fBwidgetclass\fR \fIname\fR
.sp
\fBhulltype\fR \fItype\fR
.sp
\fBsnit::widgetadaptor\fR \fIname\fR \fIdefinition\fR
.sp
\fBsnit::typemethod\fR \fItype\fR \fIname\fR \fIarglist\fR \fIbody\fR
.sp
\fBsnit::method\fR \fItype\fR \fIname\fR \fIarglist\fR \fIbody\fR
.sp
\fBsnit::macro\fR \fIname\fR \fIarglist\fR \fIbody\fR
.sp
\fBsnit::compile\fR \fIwhich\fR \fItype\fR \fIbody\fR
.sp
\fB$type\fR \fItypemethod\fR \fIargs\fR\&.\&.\&.
.sp
\fB$type\fR \fBcreate\fR \fIname\fR ?\fIoption\fR \fIvalue\fR \&.\&.\&.?
.sp
\fB$type\fR \fBinfo typevars\fR ?\fIpattern\fR?
.sp
\fB$type\fR \fBinfo typemethods\fR ?\fIpattern\fR?
.sp
\fB$type\fR \fBinfo args\fR \fImethod\fR
.sp
\fB$type\fR \fBinfo body\fR \fImethod\fR
.sp
\fB$type\fR \fBinfo default\fR \fImethod\fR \fIaname\fR \fIvarname\fR
.sp
\fB$type\fR \fBinfo instances\fR ?\fIpattern\fR?
.sp
\fB$type\fR \fBdestroy\fR
.sp
\fB$object\fR \fImethod\fR \fIargs\&.\&.\&.\fR
.sp
\fB$object\fR \fBconfigure\fR ?\fIoption\fR? ?\fIvalue\fR? \&.\&.\&.
.sp
\fB$object\fR \fBconfigurelist\fR \fIoptionlist\fR
.sp
\fB$object\fR \fBcget\fR \fIoption\fR
.sp
\fB$object\fR \fBdestroy\fR
.sp
\fB$object\fR \fBinfo type\fR
.sp
\fB$object\fR \fBinfo vars\fR ?\fIpattern\fR?
.sp
\fB$object\fR \fBinfo typevars\fR ?\fIpattern\fR?
.sp
\fB$object\fR \fBinfo typemethods\fR ?\fIpattern\fR?
.sp
\fB$object\fR \fBinfo options\fR ?\fIpattern\fR?
.sp
\fB$object\fR \fBinfo methods\fR ?\fIpattern\fR?
.sp
\fB$object\fR \fBinfo args\fR \fImethod\fR
.sp
\fB$object\fR \fBinfo body\fR \fImethod\fR
.sp
\fB$object\fR \fBinfo default\fR \fImethod\fR \fIaname\fR \fIvarname\fR
.sp
\fBmymethod\fR \fIname\fR ?\fIargs\&.\&.\&.\fR?
.sp
\fBmytypemethod\fR \fIname\fR ?\fIargs\&.\&.\&.\fR?
.sp
\fBmyproc\fR \fIname\fR ?\fIargs\&.\&.\&.\fR?
.sp
\fBmyvar\fR \fIname\fR
.sp
\fBmytypevar\fR \fIname\fR
.sp
\fBfrom\fR \fIargvName\fR \fIoption\fR ?\fIdefvalue\fR?
.sp
\fBinstall\fR \fIcompName\fR \fBusing\fR \fIobjType\fR \fIobjName\fR \fIargs\&.\&.\&.\fR
.sp
\fBinstallhull\fR \fBusing\fR \fIwidgetType\fR \fIargs\&.\&.\&.\fR
.sp
\fBinstallhull\fR \fIname\fR
.sp
\fBvariable\fR \fIname\fR
.sp
\fBtypevariable\fR \fIname\fR
.sp
\fBvarname\fR \fIname\fR
.sp
\fBtypevarname\fR \fIname\fR
.sp
\fBcodename\fR \fIname\fR
.sp
\fBsnit::boolean\fR \fBvalidate\fR ?\fIvalue\fR?
.sp
\fBsnit::boolean\fR \fIname\fR
.sp
\fBsnit::double\fR \fBvalidate\fR ?\fIvalue\fR?
.sp
\fBsnit::double\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
.sp
\fBsnit::enum\fR \fBvalidate\fR ?\fIvalue\fR?
.sp
\fBsnit::enum\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
.sp
\fBsnit::fpixels\fR \fBvalidate\fR ?\fIvalue\fR?
.sp
\fBsnit::fpixels\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
.sp
\fBsnit::integer\fR \fBvalidate\fR ?\fIvalue\fR?
.sp
\fBsnit::integer\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
.sp
\fBsnit::listtype\fR \fBvalidate\fR ?\fIvalue\fR?
.sp
\fBsnit::listtype\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
.sp
\fBsnit::pixels\fR \fBvalidate\fR ?\fIvalue\fR?
.sp
\fBsnit::pixels\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
.sp
\fBsnit::stringtype\fR \fBvalidate\fR ?\fIvalue\fR?
.sp
\fBsnit::stringtype\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
.sp
\fBsnit::window\fR \fBvalidate\fR ?\fIvalue\fR?
.sp
\fBsnit::window\fR \fIname\fR
.sp
.BE
.SH DESCRIPTION
.PP
Snit is a pure Tcl object and megawidget system\&.  It's
unique among Tcl object systems in that it's based not on inheritance
but on delegation\&.  Object systems based on inheritance only allow you
to inherit from classes defined using the same system, which is
limiting\&.  In Tcl, an object is
anything that acts like an object; it shouldn't matter how the object
was implemented\&.  Snit is intended to help you build applications out of
the materials at hand; thus, Snit is designed to be able to
incorporate and build on any object, whether it's a hand-coded object,
a \fBTk\fR widget, an \fBIncr Tcl\fR object,
a \fBBWidget\fR or almost anything else\&.
.PP
This man page is intended to be a reference only; see the accompanying
\fBsnitfaq\fR for a gentler, more tutorial introduction to Snit
concepts\&.
.SH "SNIT VERSIONS"
This man page covers both Snit 2\&.2 and Snit 1\&.3\&.  The primary
difference between the two versions is simply that Snit 2\&.2 contains
speed optimizations based on new features of Tcl 8\&.5; Snit 1\&.3
supports all of Tcl 8\&.3, 8\&.4 and Tcl 8\&.5\&.  There are a few minor
inconsistencies; they are flagged in the body of the man page with the
label "Snit 1\&.x Incompatibility"; they are also discussed in the \fBsnitfaq\fR\&.
.PP
.SH REFERENCE
.SS "TYPE AND WIDGET DEFINITIONS"
Snit provides the following commands for defining new types:
.TP
\fBsnit::type\fR \fIname\fR \fIdefinition\fR
Defines a new abstract data type called \fIname\fR\&.  If \fIname\fR is
not a fully qualified command name, it is assumed to be a name in the
namespace in which the \fBsnit::type\fR command was called (usually the
global namespace)\&.  It returns the fully qualified name of the new type\&.
.sp
The type name is then a command that is used to create objects of the
new type, along with other activities\&.
.sp
The \fBsnit::type\fR \fIdefinition\fR block is a script that may
contain the following definitions:
.RS
.TP
\fBtypevariable\fR \fIname\fR ?\fB-array\fR? ?\fIvalue\fR?
Defines a type variable with the specified \fIname\fR, and optionally
the specified \fIvalue\fR\&.  Type variables are shared by all instances
of the type\&.  If the \fB-array\fR option is included, then
\fIvalue\fR should be a dictionary; it will be
assigned to the variable using \fBarray set\fR\&.
.TP
\fBtypemethod\fR \fIname\fR \fIarglist\fR \fIbody\fR
Defines a type method, a subcommand of the new type command,
with the specified name, argument list, and
body\&.  The \fIarglist\fR is a normal Tcl argument list and may contain
default arguments and the \fBargs\fR argument; however, it may not
contain the argument names \fBtype\fR, \fBself\fR, \fBselfns\fR, or
\fBwin\fR\&.
.sp
The variable \fBtype\fR is automatically defined in the \fIbody\fR to
the type's fully-qualified name\&.  In addition,
type variables are automatically visible in the \fIbody\fR
of every type method\&.
.sp
If the \fIname\fR consists of two or more tokens, Snit handles it specially:
.CS

    typemethod {a b} {arg} { puts "Got $arg" }

.CE
.IP
This statement implicitly defines a type method called \fBa\fR which
has a subcommand \fBb\fR\&.  \fBb\fR is called like this:
.CS

    $type a b "Hello, world!"

.CE
.IP
\fBa\fR may have any number of subcommands\&.  This makes it possible
to define a hierarchical command structure; see \fBmethod\fR, below,
for more examples\&.
.sp
Type methods can call commands from the namespace in which the type is
defined without importing them, e\&.g\&., if the type name is
\fB::parentns::typename\fR, then the type's type methods can call
\fB::parentns::someproc\fR just as \fBsomeproc\fR\&.
\fISnit 1\&.x Incompatibility:\fR This does not work in Snit 1\&.x, as
it depends on \fBnamespace path\fR, a new command in Tcl 8\&.5\&.
.sp
\fISnit 1\&.x Incompatibility:\fR In Snit 1\&.x, the following
following two calls to this type method are equivalent:
.CS

    $type a b "Hello, world!"
    $type {a b} "Hello, world!"

.CE
.IP
In Snit 2\&.2, the second form is invalid\&.
.TP
\fBtypeconstructor\fR \fIbody\fR
The type constructor's \fIbody\fR is executed once when the
type is first defined; it is typically used to
initialize array-valued type variables and to add
entries to \fBThe Tk Option Database\fR\&.
.sp
The variable \fBtype\fR is automatically defined in the \fIbody\fR,
and contains the type's fully-qualified name\&.  In addition,
type variables are automatically visible in the \fIbody\fR of the type
constructor\&.
.sp
A type may define at most one type constructor\&.
.sp
The type constructor can call commands from the namespace in which the type is
defined without importing them, e\&.g\&., if the type name is
\fB::parentns::typename\fR, then the type constructor can call
\fB::parentns::someproc\fR just as \fBsomeproc\fR\&.
\fISnit 1\&.x Incompatibility:\fR This does not work in Snit 1\&.x, as
it depends on \fBnamespace path\fR, a new command in Tcl 8\&.5\&.
.TP
\fBvariable\fR \fIname\fR ?\fB-array\fR? ?\fIvalue\fR?
Defines an instance variable, a private variable associated with each
instance of this type, and optionally its initial value\&.
If the \fB-array\fR option is included, then
\fIvalue\fR should be a dictionary; it will be
assigned to the variable using \fBarray set\fR\&.
.TP
\fBmethod\fR \fIname\fR \fIarglist\fR \fIbody\fR
Defines an instance method, a subcommand of each instance of this
type, with the specified name, argument list and body\&.
The \fIarglist\fR is a normal Tcl argument list and may contain
default arguments and the \fBargs\fR argument\&.
.sp
The method is implicitly passed the following arguments as well:
\fBtype\fR, which contains the fully-qualified type name; \fBself\fR,
which contains the current instance command name; \fBselfns\fR, which
contains the name of the instance's private namespace; and \fBwin\fR,
which contains the original instance name\&.
Consequently, the \fIarglist\fR may not contain the argument names
\fBtype\fR, \fBself\fR, \fBselfns\fR, or \fBwin\fR\&.
.sp
An instance method defined in this way is said to be
\fIlocally defined\fR\&.
.sp
Type and instance variables are
automatically visible in all instance methods\&.  If the type has
locally defined options, the \fBoptions\fR array is also visible\&.
.sp
If the \fIname\fR consists of two or more tokens, Snit handles it specially:
.CS

    method {a b} {} { \&.\&.\&. }

.CE
.IP
This statement implicitly defines a method called \fBa\fR which
has a subcommand \fBb\fR\&.  \fBb\fR is called like this:
.CS

    $self a b "Hello, world!"

.CE
.IP
\fBa\fR may have any number of subcommands\&.  This makes it possible
to define a hierarchical command structure:
.CS

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

.CE
.IP
What we've done is implicitly defined a "tail" method with subcommands
"wag" and "droop"\&.  Consequently, it's an error to define "tail"
explicitly\&.
.sp
Methods can call commands from the namespace in which the type is
defined without importing them, e\&.g\&., if the type name is
\fB::parentns::typename\fR, then the type's methods can call
\fB::parentns::someproc\fR just as \fBsomeproc\fR\&.
\fISnit 1\&.x Incompatibility:\fR This does not work in Snit 1\&.x, as
it depends on \fBnamespace path\fR, a new command in Tcl 8\&.5\&.
.sp
\fISnit 1\&.x Incompatibility:\fR In Snit 1\&.x, the following
following two calls to this method are equivalent:
.CS

    $self a b "Hello, world!"
    $self {a b} "Hello, world!"

.CE
.IP
In Snit 2\&.2, the second form is invalid\&.
.TP
\fBoption\fR \fInamespec\fR ?\fIdefaultValue\fR?
.TP
\fBoption\fR \fInamespec\fR ?\fIoptions\&.\&.\&.\fR?
Defines an option for instances of this type, and optionally gives it
an initial value\&.  The initial value defaults to the empty string if
no \fIdefaultValue\fR is specified\&.
.sp
An option defined in this way is said to be \fIlocally defined\fR\&.
.sp
The \fInamespec\fR is a list defining the option's
name, resource name, and class name, e\&.g\&.:
.CS

    option {-font font Font} {Courier 12}

.CE
.IP
The option name must begin with a hyphen, and must not contain any
upper case letters\&. The resource name and class name are optional; if
not specified, the resource name defaults to the option name, minus
the hyphen, and the class name defaults to the resource name with the
first letter capitalized\&.  Thus, the following statement is equivalent
to the previous example:
.CS

    option -font {Courier 12}

.CE
.IP
See \fBThe Tk Option Database\fR for more information about
resource and class names\&.
.sp
Options are normally set and retrieved using the standard
instance methods \fBconfigure\fR and \fBcget\fR; within instance code
(method bodies, etc\&.), option values are available through the
\fBoptions\fR array:
.CS

    set myfont $options(-font)

.CE
.IP
If the type defines any option handlers (e\&.g\&., \fB-configuremethod\fR),
then it should probably use \fBconfigure\fR and \fBcget\fR to
access its options to avoid subtle errors\&.
.sp
The \fBoption\fR statement may include the following options:
.RS
.TP
\fB-default\fR \fIdefvalue\fR
Defines the option's default value; the option's default value
will be "" otherwise\&.
.TP
\fB-readonly\fR \fIflag\fR
The \fIflag\fR can be any Boolean value recognized by Tcl\&.
If \fIflag\fR is true, then the option is read-only--it can only
be set using \fBconfigure\fR or \fBconfigurelist\fR
at creation time, i\&.e\&., in the type's constructor\&.
.TP
\fB-type\fR \fItype\fR
Every locally-defined option may define its validation type, which may
be either the name of a validation type or a specification for a
validation subtype
.sp
For example, an option may declare that its value must be an integer
by specifying \fBsnit::integer\fR as its validation type:
.CS

    option -number -type snit::integer

.CE
.IP
It may also declare that its value is an integer between 1 and 10
by specifying a validation subtype:
.CS

    option -number -type {snit::integer -min 1 -max 10}

.CE
.IP
If a validation type or subtype is defined for an option, then
it will be used to validate the option's value whenever it is
changed by the object's \fBconfigure\fR or
\fBconfigurelist\fR methods\&.  In addition, all such options
will have their values validated automatically immediately
after the constructor executes\&.
.sp
Snit defines a family of validation types and subtypes, and it's
quite simple to define new ones\&.  See
\fBValidation Types\fR for the complete list, and
\fBDefining Validation Types\fR for an explanation of how
to define your own\&.
.TP
\fB-cgetmethod\fR \fImethodName\fR
Every locally-defined option may define a \fB-cgetmethod\fR;
it is called when the option's value is retrieved using the
\fBcget\fR method\&.  Whatever the method's \fIbody\fR returns will
be the return value of the call to \fBcget\fR\&.
.sp
The named method must take one argument, the option name\&.
For example, this code is equivalent to (though slower than)
Snit's default handling of \fBcget\fR:
.CS

    option -font -cgetmethod GetOption
    method GetOption {option} {
        return $options($option)
    }

.CE
.IP
Note that it's possible for any number of options to share a
\fB-cgetmethod\fR\&.
.TP
\fB-configuremethod\fR \fImethodName\fR
Every locally-defined option may define a \fB-configuremethod\fR;
it is called when the option's value is set using the
\fBconfigure\fR or \fBconfigurelist\fR methods\&.  It is the
named method's responsibility to save the option's value; in other
words, the value will not be saved to the \fBoptions()\fR array unless
the method saves it there\&.
.sp
The named method must take two arguments, the option name and
its new value\&.  For example, this code is equivalent to
(though slower than) Snit's default handling of \fBconfigure\fR:
.CS

    option -font -configuremethod SetOption
    method SetOption {option value} {
        set options($option) $value
    }

.CE
.IP
Note that it's possible for any number of options to share a
single \fB-configuremethod\fR\&.
.TP
\fB-validatemethod\fR \fImethodName\fR
Every locally-defined option may define a \fB-validatemethod\fR;
it is called when the option's value is set using the
\fBconfigure\fR or \fBconfigurelist\fR methods, just before
the \fB-configuremethod\fR (if any)\&.  It is the
named method's responsibility to validate the option's new value,
and to throw an error if the value is invalid\&.
.sp
The named method must take two arguments, the option name and
its new value\&.  For example, this code verifies that
\fB-flag\fR's value is a valid Boolean value:
.CS

    option -font -validatemethod CheckBoolean
    method CheckBoolean {option value} {
        if {![string is boolean -strict $value]} {
            error "option $option must have a boolean value\&."
        }
    }

.CE
.IP
Note that it's possible for any number of options to share a
single \fB-validatemethod\fR\&.
.RE
.TP
\fBconstructor\fR \fIarglist\fR \fIbody\fR
The constructor definition specifies a \fIbody\fR of code to be
executed when a new instance is created\&.  The \fIarglist\fR is a
normal Tcl argument list and may contain default arguments and
the \fBargs\fR argument\&.
.sp
As with methods, the arguments \fBtype\fR, \fBself\fR, \fBselfns\fR,
and \fBwin\fR are defined implicitly, and all type and instance
variables are automatically visible in its \fIbody\fR\&.
.sp
If the \fIdefinition\fR doesn't explicitly define the constructor,
Snit defines one implicitly\&.  If the type declares at least one option
(whether locally or by delegation), the default constructor will
be defined as follows:
.CS

    constructor {args} {
        $self configurelist $args
    }

.CE
.IP
For standard Tk widget behavior, the argument list should be
the single name \fBargs\fR, as shown\&.
.sp
If the \fIdefinition\fR defines neither a constructor nor
any options, the default constructor is defined as follows:
.CS

    constructor {} {}

.CE
.IP
As with methods, the constructor can call commands from the namespace
in which the type is
defined without importing them, e\&.g\&., if the type name is
\fB::parentns::typename\fR, then the constructor can call
\fB::parentns::someproc\fR just as \fBsomeproc\fR\&.
\fISnit 1\&.x Incompatibility:\fR This does not work in Snit 1\&.x, as
it depends on \fBnamespace path\fR, a new command in Tcl 8\&.5\&.
.TP
\fBdestructor\fR \fIbody\fR
The destructor is used to code any actions that must take place when
an instance of the type is destroyed: typically, the destruction of
anything created in the constructor\&.
.sp
The destructor takes no explicit arguments; as with methods, the
arguments \fBtype\fR, \fBself\fR, \fBselfns\fR, and \fBwin\fR, are
defined implicitly, and all type and instance
variables are automatically visible in its \fIbody\fR\&.
As with methods, the destructor can call commands from the namespace
in which the type is
defined without importing them, e\&.g\&., if the type name is
\fB::parentns::typename\fR, then the destructor can call
\fB::parentns::someproc\fR just as \fBsomeproc\fR\&.
\fISnit 1\&.x Incompatibility:\fR This does not work in Snit 1\&.x, as
it depends on \fBnamespace path\fR, a new command in Tcl 8\&.5\&.
.TP
\fBproc\fR \fIname\fR \fIargs\fR \fIbody\fR
Defines a new Tcl procedure in the type's namespace\&.
.sp
The defined proc differs from a normal Tcl proc in that all type
variables are automatically visible\&.  The proc can access
instance variables as well, provided that it is passed
\fBselfns\fR (with precisely that name) as one of its arguments\&.
.sp
Although they are not implicitly defined for procs, the argument names
\fBtype\fR, \fBself\fR, and \fBwin\fR should be avoided\&.
.sp
As with methods and typemethods, procs can call commands from the namespace
in which the type is
defined without importing them, e\&.g\&., if the type name is
\fB::parentns::typename\fR, then the proc can call
\fB::parentns::someproc\fR just as \fBsomeproc\fR\&.
\fISnit 1\&.x Incompatibility:\fR This does not work in Snit 1\&.x, as
it depends on \fBnamespace path\fR, a new command in Tcl 8\&.5\&.
.TP
\fBdelegate\fR \fBmethod\fR \fIname\fR \fBto\fR \fIcomp\fR ?\fBas\fR \fItarget\fR?
Delegates method \fIname\fR to component \fIcomp\fR\&.  That is, when
method \fIname\fR is called on an instance of this type, the method
and its arguments will be passed to the named component's command
instead\&.  That is, the following statement
.CS

    delegate method wag to tail

.CE
.IP
is roughly equivalent to this explicitly defined method:
.CS

    method wag {args} {
        uplevel $tail wag $args
    }

.CE
.IP
As with methods, the \fIname\fR may have multiple tokens; in this
case, the last token of the name is assumed to be the name of the
component's method\&.
.sp
The optional \fBas\fR clause allows you to specify the delegated
method name and possibly add some arguments:
.CS

    delegate method wagtail to tail as "wag briskly"

.CE
.sp
A method cannot be both locally defined and delegated\&.
.sp
\fBNote:\fR All forms of \fBdelegate method\fR can delegate to
both instance components and type components\&.
.TP
\fBdelegate\fR \fBmethod\fR \fIname\fR ?\fBto\fR \fIcomp\fR? \fBusing\fR \fIpattern\fR
In this form of the \fBdelegate\fR statement, the \fBusing\fR clause
is used to specify the precise form of the command to which method
\fIname\fR name is delegated\&.  In this form, the \fBto\fR clause is
optional, since the chosen command might not involve any particular
component\&.
.sp
The value of the \fBusing\fR clause is a list that may contain
any or all of the following substitution codes; these codes are
substituted with the described value to build the delegated command
prefix\&.  Note that the following two statements are equivalent:
.CS

    delegate method wag to tail
    delegate method wag to tail using "%c %m"

.CE
.IP
Each element of the list becomes a single element of the delegated
command--it is never reparsed as a string\&.
.sp
Substitutions:
.RS
.TP
\fB%%\fR
This is replaced with a single "%"\&.  Thus, to pass the string "%c"
to the command as an argument, you'd write "%%c"\&.
.TP
\fB%c\fR
This is replaced with the named component's command\&.
.TP
\fB%m\fR
This is replaced with the final token of the method \fIname\fR; if
the method \fIname\fR has one token, this is identical to \fB%M\fR\&.
.TP
\fB%M\fR
This is replaced by the method \fIname\fR; if the \fIname\fR consists
of multiple tokens, they are joined by space characters\&.
.TP
\fB%j\fR
This is replaced by the method \fIname\fR; if the \fIname\fR consists
of multiple tokens, they are joined by underscores ("_")\&.
.TP
\fB%t\fR
This is replaced with the fully qualified type name\&.
.TP
\fB%n\fR
This is replaced with the name of the instance's private namespace\&.
.TP
\fB%s\fR
This is replaced with the name of the instance command\&.
.TP
\fB%w\fR
This is replaced with the original name of the instance command; for
Snit widgets and widget adaptors, it will be the Tk window name\&.
It remains constant, even if the instance command is renamed\&.
.RE
.TP
\fBdelegate\fR \fBmethod\fR \fB*\fR ?\fBto\fR \fIcomp\fR? ?\fBusing\fR \fIpattern\fR? ?\fBexcept\fR \fIexceptions\fR?
The form \fBdelegate method *\fR delegates all unknown method names to the
specified \fIcomp\fRonent\&.  The \fBexcept\fR clause can be used to
specify a list of \fIexceptions\fR, i\&.e\&., method names that will not
be so delegated\&. The \fBusing\fR clause is defined as given above\&.
In this form, the statement must contain the \fBto\fR clause, the
\fBusing\fR clause, or both\&.
.sp
In fact, the "*" can be a list of two or more tokens whose last
element is "*", as in the following example:
.CS

    delegate method {tail *} to tail

.CE
.IP
This implicitly defines the method \fBtail\fR whose subcommands will
be delegated to the \fBtail\fR component\&.
.TP
\fBdelegate\fR \fBoption\fR \fInamespec\fR \fBto\fR \fIcomp\fR
.TP
\fBdelegate\fR \fBoption\fR \fInamespec\fR \fBto\fR \fIcomp\fR \fBas\fR \fItarget\fR
.TP
\fBdelegate\fR \fBoption\fR \fB*\fR \fBto\fR \fIcomp\fR
.TP
\fBdelegate\fR \fBoption\fR \fB*\fR \fBto\fR \fIcomp\fR \fBexcept\fR \fIexceptions\fR
Defines a delegated option; the \fInamespec\fR is defined as for the
\fBoption\fR statement\&.
When the \fBconfigure\fR, \fBconfigurelist\fR, or \fBcget\fR
instance method is used to set or retrieve the option's value, the
equivalent \fBconfigure\fR or \fBcget\fR command will be applied
to the component as though the option was defined with the following
\fB-configuremethod\fR and \fB-cgetmethod\fR:
.CS

    method ConfigureMethod {option value} {
        $comp configure $option $value
    }

    method CgetMethod {option} {
        return [$comp cget $option]
    }

.CE
.IP
Note that delegated options never appear in the \fBoptions\fR array\&.
.sp
If the \fBas\fR clause is specified, then the \fItarget\fR option
name is used in place of \fIname\fR\&.
.sp
The form \fBdelegate option *\fR delegates all unknown options to the
specified \fIcomp\fRonent\&.  The \fBexcept\fR clause can be used to
specify a list of \fIexceptions\fR, i\&.e\&., option names that will not
be so delegated\&.
.sp
Warning: options can only be delegated to a component if it supports
the \fBconfigure\fR and \fBcget\fR instance methods\&.
.sp
An option cannot be both locally defined and delegated\&.
TBD: Continue from here\&.
.TP
\fBcomponent\fR \fIcomp\fR ?\fB-public\fR \fImethod\fR? ?\fB-inherit\fR \fIflag\fR?
Explicitly declares a component called \fIcomp\fR, and automatically
defines the component's instance variable\&.
.sp
If the \fB-public\fR option is specified, then the option is made
public by defining a \fImethod\fR whose subcommands are delegated
to the component e\&.g\&., specifying \fB-public mycomp\fR is
equivalent to the following:
.CS

    component mycomp
    delegate method {mymethod *} to mycomp

.CE
.IP
If the \fB-inherit\fR option is specified, then \fIflag\fR must be a
Boolean value; if \fIflag\fR is true then all unknown methods and
options will be delegated to this component\&.  The name \fB-inherit\fR
implies that instances of this new type inherit, in a sense, the
methods and options of the component\&. That is, \fB-inherit yes\fR is
equivalent to:
.CS

    component mycomp
    delegate option * to mycomp
    delegate method * to mycomp

.CE
.TP
\fBdelegate\fR \fBtypemethod\fR \fIname\fR \fBto\fR \fIcomp\fR ?\fBas\fR \fItarget\fR?
Delegates type method \fIname\fR to type component \fIcomp\fR\&.  That is, when
type method \fIname\fR is called on this type, the type method
and its arguments will be passed to the named type component's command
instead\&.  That is, the following statement
.CS

    delegate typemethod lostdogs to pound

.CE
.IP
is roughly equivalent to this explicitly defined method:
.CS

    typemethod lostdogs {args} {
        uplevel $pound lostdogs $args
    }

.CE
.IP
As with type methods, the \fIname\fR may have multiple tokens; in this
case, the last token of the name is assumed to be the name of the
component's method\&.
.sp
The optional \fBas\fR clause allows you to specify the delegated
method name and possibly add some arguments:
.CS

    delegate typemethod lostdogs to pound as "get lostdogs"

.CE
.sp
A type method cannot be both locally defined and delegated\&.
.TP
\fBdelegate\fR \fBtypemethod\fR \fIname\fR ?\fBto\fR \fIcomp\fR? \fBusing\fR \fIpattern\fR
In this form of the \fBdelegate\fR statement, the \fBusing\fR clause
is used to specify the precise form of the command to which type method
\fIname\fR name is delegated\&.  In this form, the \fBto\fR clause is
optional, since the chosen command might not involve any particular
type component\&.
.sp
The value of the \fBusing\fR clause is a list that may contain
any or all of the following substitution codes; these codes are
substituted with the described value to build the delegated command
prefix\&.  Note that the following two statements are equivalent:
.CS

    delegate typemethod lostdogs to pound
    delegate typemethod lostdogs to pound using "%c %m"

.CE
.IP
Each element of the list becomes a single element of the delegated
command--it is never reparsed as a string\&.
.sp
Substitutions:
.RS
.TP
\fB%%\fR
This is replaced with a single "%"\&.  Thus, to pass the string "%c"
to the command as an argument, you'd write "%%c"\&.
.TP
\fB%c\fR
This is replaced with the named type component's command\&.
.TP
\fB%m\fR
This is replaced with the final token of the type method \fIname\fR; if
the type method \fIname\fR has one token, this is identical to \fB%M\fR\&.
.TP
\fB%M\fR
This is replaced by the type method \fIname\fR; if the \fIname\fR consists
of multiple tokens, they are joined by space characters\&.
.TP
\fB%j\fR
This is replaced by the type method \fIname\fR; if the \fIname\fR consists
of multiple tokens, they are joined by underscores ("_")\&.
.TP
\fB%t\fR
This is replaced with the fully qualified type name\&.
.RE
.TP
\fBdelegate\fR \fBtypemethod\fR \fB*\fR ?\fBto\fR \fIcomp\fR? ?\fBusing\fR \fIpattern\fR? ?\fBexcept\fR \fIexceptions\fR?
The form \fBdelegate typemethod *\fR delegates all unknown type
method names to the
specified type component\&.  The \fBexcept\fR clause can be used to
specify a list of \fIexceptions\fR, i\&.e\&., type method names that will not
be so delegated\&. The \fBusing\fR clause is defined as given above\&.
In this form, the statement must contain the \fBto\fR clause, the
\fBusing\fR clause, or both\&.
.sp
\fBNote:\fR By default, Snit interprets \fB$type foo\fR, where
\fBfoo\fR is
not a defined type method, as equivalent to \fB$type create foo\fR, where
\fBfoo\fR is the name of a new instance of the type\&.  If you
use \fBdelegate typemethod *\fR, then the \fBcreate\fR type
method must always be used explicitly\&.
.sp
The "*" can be a list of two or more tokens whose last
element is "*", as in the following example:
.CS

    delegate typemethod {tail *} to tail

.CE
.IP
This implicitly defines the type method \fBtail\fR whose subcommands will
be delegated to the \fBtail\fR type component\&.
.TP
\fBtypecomponent\fR \fIcomp\fR ?\fB-public\fR \fItypemethod\fR? ?\fB-inherit\fR \fIflag\fR?
Explicitly declares a type component called \fIcomp\fR, and automatically
defines the component's type variable\&.  A type component is an arbitrary
command to which type methods and instance methods can be delegated;
the command's name is stored in a type variable\&.
.sp
If the \fB-public\fR option is specified, then the type component is made
public by defining a \fItypemethod\fR whose subcommands are delegated to
the type component, e\&.g\&., specifying \fB-public mytypemethod\fR
is equivalent to the following:
.CS

    typecomponent mycomp
    delegate typemethod {mytypemethod *} to mycomp

.CE
.IP
If the \fB-inherit\fR option is specified, then \fIflag\fR must be a
Boolean value; if \fIflag\fR is true then all unknown type methods
will be delegated to this type component\&. (See the note on "delegate
typemethod *", above\&.) The name \fB-inherit\fR
implies that this type inherits, in a sense, the behavior of
the type component\&. That is, \fB-inherit yes\fR is equivalent to:
.CS

    typecomponent mycomp
    delegate typemethod * to mycomp

.CE
.TP
\fBpragma\fR ?\fIoptions\&.\&.\&.\fR?
The \fBpragma\fR statement provides control over how Snit generates a
type\&.  It takes the following options; in each case, \fIflag\fR must
be a Boolean value recognized by Tcl, e\&.g\&., \fB0\fR, \fB1\fR,
\fByes\fR, \fBno\fR, and so
on\&.
.sp
By setting the \fB-hastypeinfo\fR, \fB-hastypedestroy\fR, and
\fB-hasinstances\fR pragmas to false and defining appropriate
type methods, you can create an ensemble command without any extraneous
behavior\&.
.RS
.TP
\fB-canreplace\fR \fIflag\fR
If false (the default) Snit will not create an instance of a
\fBsnit::type\fR that has the same name as an existing command; this
prevents subtle errors\&.  Setting this pragma to true restores the
behavior of Snit V0\&.93 and earlier versions\&.
.TP
\fB-hastypeinfo\fR \fIflag\fR
If true (the default), the generated type will have a type method
called \fBinfo\fR that is used for type introspection; the \fBinfo\fR
type method is documented below\&.  If false, it will not\&.
.TP
\fB-hastypedestroy\fR \fIflag\fR
If true (the default), the generated type will have a type method
called \fBdestroy\fR that is used to destroy the type and all of its
instances\&.  The \fBdestroy\fR type method is documented below\&.  If
false, it will not\&.
.TP
\fB-hastypemethods\fR \fIflag\fR
If true (the default), the generated type's type command will have
subcommands (type methods) as usual\&.  If false, the type command
will serve only to create instances of the type; the first argument
is the instance name\&.
.sp
This pragma and \fB-hasinstances\fR cannot both be set false\&.
.TP
\fB-hasinstances\fR \fIflag\fR
If true (the default), the generated type will have a type method
called \fBcreate\fR that is used to create instances of the type,
along with a variety of instance-related features\&.  If false, it will
not\&.
.sp
This pragma and \fB-hastypemethods\fR cannot both be set false\&.
.TP
\fB-hasinfo\fR \fIflag\fR
If true (the default), instances of the generated type will have
an instance method called \fBinfo\fR that is used for
instance introspection; the \fBinfo\fR
method is documented below\&.  If false, it will not\&.
.TP
\fB-simpledispatch\fR \fIflag\fR
This pragma is intended to make simple, heavily-used abstract
data types (e\&.g\&., stacks and queues) more efficient\&.
.sp
If false (the default), instance methods are dispatched normally\&.  If
true, a faster dispatching scheme is used instead\&.
The speed comes at a price; with \fB-simpledispatch yes\fR you
get the following limitations:
.RS
.IP \(bu
Methods cannot be delegated\&.
.IP \(bu
\fBuplevel\fR and \fBupvar\fR do not work as expected: the
caller's scope is two levels up rather than one\&.
.IP \(bu
The option-handling methods
(\fBcget\fR, \fBconfigure\fR, and \fBconfigurelist\fR) are very
slightly slower\&.
.RE
.RE
.TP
\fBexpose\fR \fIcomp\fR
.TP
\fBexpose\fR \fIcomp\fR \fBas\fR \fImethod\fR
\fBDeprecated\&.\fR  To expose component \fIcomp\fR publicly, use
\fBcomponent\fR's \fB-public\fR option\&.
.TP
\fBonconfigure\fR \fIname\fR \fIarglist\fR \fIbody\fR
\fBDeprecated\&.\fR  Define \fBoption\fR's \fB-configuremethod\fR
option instead\&.
.sp
As of version 0\&.95, the following definitions,
.CS

    option -myoption
    onconfigure -myoption {value} {
        # Code to save the option's value
    }

.CE
.IP
are implemented as follows:
.CS

    option -myoption -configuremethod _configure-myoption
    method _configure-myoption {_option value} {
        # Code to save the option's value
    }

.CE
.TP
\fBoncget\fR \fIname\fR \fIbody\fR
\fBDeprecated\&.\fR  Define \fBoption\fR's \fB-cgetmethod\fR
option instead\&.
.sp
As of version 0\&.95, the following definitions,
.CS

    option -myoption
    oncget -myoption {
        # Code to return the option's value
    }

.CE
.IP
are implemented as follows:
.CS

    option -myoption -cgetmethod _cget-myoption
    method _cget-myoption {_option} {
        # Code to return the option's value
    }

.CE
.RE
.TP
\fBsnit::widget\fR \fIname\fR \fIdefinition\fR
This command defines a Snit megawidget type with the specified
\fIname\fR\&.  The \fIdefinition\fR is defined as for \fBsnit::type\fR\&.
A \fBsnit::widget\fR differs from a \fBsnit::type\fR
in these ways:
.RS
.IP \(bu
Every instance of a \fBsnit::widget\fR has an automatically-created
component called \fBhull\fR, which is normally a Tk frame widget\&.
Other widgets created as part of the megawidget will be created within
this widget\&.
.sp
The hull component is initially created with the requested widget
name; then Snit does some magic, renaming the hull component and
installing its own instance command in its place\&.
The hull component's new name is saved in an instance variable called
\fBhull\fR\&.
.IP \(bu
The name of an instance must be valid Tk window name, and the parent
window must exist\&.
.RE
.IP
A \fBsnit::widget\fR definition can include any of statements allowed
in a \fBsnit::type\fR definition, and may also include the following:
.RS
.TP
\fBwidgetclass\fR \fIname\fR
Sets the \fBsnit::widget\fR's widget class to \fIname\fR, overriding
the default\&.  See \fBThe Tk Option Database\fR for more
information\&.
.TP
\fBhulltype\fR \fItype\fR
Determines the kind of widget used as the \fBsnit::widget\fR's hull\&.
The \fItype\fR may be \fBframe\fR (the default), \fBtoplevel\fR,
\fBlabelframe\fR; the qualified equivalents of these,
\fBtk::frame\fR, \fBtk::toplevel\fR, and \fBtk::labelframe\fR;
or, if available, the equivalent Tile widgets:
\fBttk::frame\fR, \fBttk::toplevel\fR, and
\fBttk::labelframe\fR\&.  In practice, any widget that supports the
\fB-class\fR option can be used as a hull widget by
\fBlappend\fR'ing its name to the variable \fBsnit::hulltypes\fR\&.
.RE
.TP
\fBsnit::widgetadaptor\fR \fIname\fR \fIdefinition\fR
This command defines a Snit megawidget type with the specified name\&.
It differs from \fBsnit::widget\fR in that the instance's \fBhull\fR
component is not created automatically, but is created in the
constructor and installed using the \fBinstallhull\fR command\&.  Once
the hull is installed, its instance command is renamed and replaced as
with normal \fBsnit::widget\fRs\&.  The original command is again
accessible in the instance variable \fBhull\fR\&.
.sp
Note that in general it is not possible to change the
\fIwidget class\fR of a \fBsnit::widgetadaptor\fR's hull widget\&.
.sp
See \fBThe Tk Option Database\fR for information on how
\fBsnit::widgetadaptor\fRs interact with the option database\&.
.TP
\fBsnit::typemethod\fR \fItype\fR \fIname\fR \fIarglist\fR \fIbody\fR
Defines a new type method (or redefines an existing type method)
for a previously existing \fItype\fR\&.
.TP
\fBsnit::method\fR \fItype\fR \fIname\fR \fIarglist\fR \fIbody\fR
Defines a new instance method (or redefines an existing instance
method) for a previously existing \fItype\fR\&.  Note that delegated
instance methods can't be redefined\&.
.TP
\fBsnit::macro\fR \fIname\fR \fIarglist\fR \fIbody\fR
Defines a Snit macro with the specified \fIname\fR, \fIarglist\fR, and
\fIbody\fR\&.  Macros are used to define new type and widget
definition statements in terms of the statements defined in this man
page\&.
.sp
A macro is simply a Tcl proc that is defined in the slave interpreter
used to compile type and widget definitions\&.  Thus, macros have
access to all of the type and widget definition statements\&.  See
\fBMacros and Meta-programming\fR for more details\&.
.sp
The macro \fIname\fR cannot be the same as any standard Tcl command,
or any Snit type or widget definition statement, e\&.g\&., you can't
redefine the \fBmethod\fR or \fBdelegate\fR statements, or the
standard \fBset\fR, \fBlist\fR, or \fBstring\fR commands\&.
.TP
\fBsnit::compile\fR \fIwhich\fR \fItype\fR \fIbody\fR
Snit defines a type, widget, or widgetadaptor by "compiling" the
definition into a Tcl script; this script is then evaluated in the
Tcl interpreter, which actually defines the new type\&.
.sp
This command exposes the "compiler"\&.  Given a definition \fIbody\fR
for the named \fItype\fR, where \fIwhich\fR is \fBtype\fR,
\fBwidget\fR, or \fBwidgetadaptor\fR, \fBsnit::compile\fR returns a list
of two elements\&.  The first element is the fully qualified type name;
the second element is the definition script\&.
.sp
\fBsnit::compile\fR is useful when additional processing
must be done on the Snit-generated code--if it must be instrumented,
for example, or run through the TclDevKit compiler\&.  In addition, the
returned script could be saved in a "\&.tcl" file and used to define the
type as part of an application or library, thus saving the compilation
overhead at application start-up\&.  Note that the
same version of Snit must be used at run-time as at compile-time\&.
.PP
.SS "THE TYPE COMMAND"
A type or widget definition creates a type command, which is used to
create instances of the type\&.  The type command has this form:
.PP
.TP
\fB$type\fR \fItypemethod\fR \fIargs\fR\&.\&.\&.
The \fItypemethod\fR can be any of the
\fBStandard Type Methods\fR (e\&.g\&., \fBcreate\fR),
or any type method defined in the type
definition\&.
The subsequent \fIargs\fR depend on the specific \fItypemethod\fR
chosen\&.
.sp
The type command is most often used to create new instances of the
type; hence, the \fBcreate\fR method is assumed if the first
argument to the type command doesn't name a valid type method, unless
the type definition includes \fBdelegate typemethod *\fR or the
\fB-hasinstances\fR pragma is set to false\&.
.sp
Furthermore, if the \fB-hastypemethods\fR pragma is false, then
Snit type commands can be called with no arguments at
all; in this case, the type command creates an instance with an
automatically generated name\&.  In other words, provided that the
\fB-hastypemethods\fR pragma is false and the type
has instances, the following commands are equivalent:
.CS

snit::type dog { \&.\&.\&. }

set mydog [dog create %AUTO%]
set mydog [dog %AUTO%]
set mydog [dog]

.CE
.IP
This doesn't work for Snit widgets, for obvious reasons\&.
.sp
\fISnit 1\&.x Incompatibility:\fR In Snit 1\&.x, the above behavior is
available whether \fB-hastypemethods\fR is true (the default) or false\&.
.PP
.SS "STANDARD TYPE METHODS"
In addition to any type methods in the type's definition, all type and
widget commands will usually have at least the following subcommands:
.PP
.TP
\fB$type\fR \fBcreate\fR \fIname\fR ?\fIoption\fR \fIvalue\fR \&.\&.\&.?
Creates a new instance of the type, giving it the specified \fIname\fR
and calling the type's constructor\&.
.sp
For \fBsnit::type\fRs, if \fIname\fR is not a fully-qualified command
name, it is assumed to be a name in the namespace in which the call to
\fBsnit::type\fR appears\&.  The method returns the fully-qualified
instance name\&.
.sp
For \fBsnit::widget\fRs and \fBsnit::widgetadaptor\fRs, \fIname\fR
must be a valid widget name; the method returns the widget name\&.
.sp
So long as \fIname\fR does not conflict with any defined type method
name the \fBcreate\fR keyword may be omitted, unless
the type definition includes \fBdelegate typemethod *\fR or the
\fB-hasinstances\fR pragma is set to false\&.
.sp
If the \fIname\fR includes the string \fB%AUTO%\fR, it will be
replaced with the string \fB$type$counter\fR where \fB$type\fR is
the type name and \fB$counter\fR is a counter that increments each
time \fB%AUTO%\fR is used for this type\&.
.sp
By default, any arguments following the \fIname\fR will be a list of
\fIoption\fR names and their \fIvalue\fRs; however, a type's
constructor can specify a different argument list\&.
.sp
As of Snit V0\&.95, \fBcreate\fR will throw an error if the \fIname\fR
is the same as any existing command--note that this was always true
for \fBsnit::widget\fRs and \fBsnit::widgetadaptor\fRs\&.  You can
restore the previous behavior using the \fB-canreplace\fR pragma\&.
.TP
\fB$type\fR \fBinfo typevars\fR ?\fIpattern\fR?
Returns a list of the type's type variables (excluding Snit internal
variables); all variable names are fully-qualified\&.
.sp
If \fIpattern\fR is given, it's used as a \fBstring match\fR
pattern; only names that match the pattern are returned\&.
.TP
\fB$type\fR \fBinfo typemethods\fR ?\fIpattern\fR?
Returns a list of the names of the  type's type methods\&.
If the type has hierarchical
type methods, whether locally-defined or delegated, only the first
word of each will be included in the list\&.
.sp
If the type
definition includes \fBdelegate typemethod *\fR, the list will
include only the names of those implicitly delegated type methods
that have been called at least once and are still in the type method cache\&.
.sp
If \fIpattern\fR is given, it's used as a \fBstring match\fR
pattern; only names that match the pattern are returned\&.
.TP
\fB$type\fR \fBinfo args\fR \fImethod\fR
Returns a list containing the names of the arguments to the type's
\fImethod\fR, in order\&. This method cannot be applied to delegated
type methods\&.
.TP
\fB$type\fR \fBinfo body\fR \fImethod\fR
Returns the body of typemethod \fImethod\fR\&. This method cannot be
applied to delegated type methods\&.
.TP
\fB$type\fR \fBinfo default\fR \fImethod\fR \fIaname\fR \fIvarname\fR
Returns a boolean value indicating whether the argument \fIaname\fR of
the type's \fImethod\fR has a default value (\fBtrue\fR) or not
(\fBfalse\fR)\&. If the argument has a default its value is placed into
the variable \fIvarname\fR\&.
.TP
\fB$type\fR \fBinfo instances\fR ?\fIpattern\fR?
Returns a list of the type's instances\&.  For \fBsnit::type\fRs, it
will be a list of fully-qualified instance names;
for \fBsnit::widget\fRs, it will be a list of Tk widget names\&.
.sp
If \fIpattern\fR is given, it's used as a \fBstring match\fR
pattern; only names that match the pattern are returned\&.
.sp
\fISnit 1\&.x Incompatibility:\fR  In Snit 1\&.x, the full multi-word
names of hierarchical type methods are included in the return value\&.
.TP
\fB$type\fR \fBdestroy\fR
Destroys the type's instances, the type's namespace, and the type
command itself\&.
.PP
.SS "THE INSTANCE COMMAND"
A Snit type or widget's \fBcreate\fR type method creates objects of
the type; each object has a unique name that is also a Tcl command\&.
This command is used to access the object's methods and data, and has
this form:
.PP
.TP
\fB$object\fR \fImethod\fR \fIargs\&.\&.\&.\fR
The \fImethod\fR can be any of the
\fBStandard Instance Methods\fR, or any instance method
defined in the type definition\&.
The subsequent \fIargs\fR depend on the specific \fImethod\fR chosen\&.
.PP
.SS "STANDARD INSTANCE METHODS"
In addition to any delegated or locally-defined instance methods in
the type's definition, all Snit objects will have at least the
following subcommands:
.PP
.TP
\fB$object\fR \fBconfigure\fR ?\fIoption\fR? ?\fIvalue\fR? \&.\&.\&.
Assigns new values to one or more options\&.  If called with one
argument, an \fIoption\fR name, returns a list describing the option,
as Tk widgets do; if called with no arguments, returns a list of lists
describing all options, as Tk widgets do\&.
.sp
Warning: This information will be available for delegated options only
if the component to which they are delegated has a \fBconfigure\fR
method that returns this same kind of information\&.
.sp
Note: Snit defines this method only if the type has at least one
option\&.
.TP
\fB$object\fR \fBconfigurelist\fR \fIoptionlist\fR
Like \fBconfigure\fR, but takes one argument, a list of options and
their values\&.  It's mostly useful in the type constructor, but can be
used anywhere\&.
.sp
Note: Snit defines this method only if the type has at least one
option\&.
.TP
\fB$object\fR \fBcget\fR \fIoption\fR
Returns the option's value\&.
.sp
Note: Snit defines this method only if the type has at least one
option\&.
.TP
\fB$object\fR \fBdestroy\fR
Destroys the object, calling the \fBdestructor\fR and freeing all
related memory\&.
.sp
\fINote:\fR
The \fBdestroy\fR method isn't defined for \fBsnit::widget\fR or
\fBsnit::widgetadaptor\fR objects; instances of these are destroyed by
calling \fBTk\fR's \fBdestroy\fR command, just as normal
widgets are\&.
.TP
\fB$object\fR \fBinfo type\fR
Returns the instance's type\&.
.TP
\fB$object\fR \fBinfo vars\fR ?\fIpattern\fR?
Returns a list of the object's instance variables (excluding Snit
internal variables)\&.  The names are fully qualified\&.
.sp
If \fIpattern\fR is given, it's used as a \fBstring match\fR
pattern; only names that match the pattern are returned\&.
.TP
\fB$object\fR \fBinfo typevars\fR ?\fIpattern\fR?
Returns a list of the object's type's type variables (excluding Snit
internal variables)\&.  The names are fully qualified\&.
.sp
If \fIpattern\fR is given, it's used as a \fBstring match\fR
pattern; only names that match the pattern are returned\&.
.TP
\fB$object\fR \fBinfo typemethods\fR ?\fIpattern\fR?
Returns a list of the names of the  type's type methods\&.
If the type has hierarchical
type methods, whether locally-defined or delegated, only the first
word of each will be included in the list\&.
.sp
If the type
definition includes \fBdelegate typemethod *\fR, the list will
include only the names of those implicitly delegated type methods
that have been called at least once and are still in the type method cache\&.
.sp
If \fIpattern\fR is given, it's used as a \fBstring match\fR
pattern; only names that match the pattern are returned\&.
.sp
\fISnit 1\&.x Incompatibility:\fR  In Snit 1\&.x, the full multi-word
names of hierarchical type methods are included in the return value\&.
.TP
\fB$object\fR \fBinfo options\fR ?\fIpattern\fR?
Returns a list of the object's option names\&.  This always includes
local options and explicitly delegated options\&.  If unknown options
are delegated as well, and if the component to which they are
delegated responds to \fB$object configure\fR like Tk widgets do,
then the result will include all possible unknown options that can
be delegated to the component\&.
.sp
If \fIpattern\fR is given, it's used as a \fBstring match\fR
pattern; only names that match the pattern are returned\&.
.sp
Note that the return value might be different for different instances
of the same type, if component object types can vary from one instance
to another\&.
.TP
\fB$object\fR \fBinfo methods\fR ?\fIpattern\fR?
Returns a list of the names of the instance's methods\&.
If the type has hierarchical methods, whether locally-defined or
delegated, only the first word of each will be included in the list\&.
.sp
If the type
definition includes \fBdelegate method *\fR, the list will
include only the names of those implicitly delegated methods that have
been called at least once and are still in the method cache\&.
.sp
If \fIpattern\fR is given, it's used as a \fBstring match\fR
pattern; only names that match the pattern are returned\&.
.sp
\fISnit 1\&.x Incompatibility:\fR  In Snit 1\&.x, the full multi-word
names of hierarchical type methods are included in the return value\&.
.TP
\fB$object\fR \fBinfo args\fR \fImethod\fR
Returns a list containing the names of the arguments to the instance's
\fImethod\fR, in order\&. This method cannot be applied to delegated methods\&.
.TP
\fB$object\fR \fBinfo body\fR \fImethod\fR
Returns the body of the instance's method \fImethod\fR\&. This method
cannot be applied to delegated methods\&.
.TP
\fB$object\fR \fBinfo default\fR \fImethod\fR \fIaname\fR \fIvarname\fR
Returns a boolean value indicating whether the argument \fIaname\fR of
the instance's \fImethod\fR has a default value (\fBtrue\fR) or not
(\fBfalse\fR)\&. If the argument has a default its value is placed into
the variable \fIvarname\fR\&.
.PP
.SS "COMMANDS FOR USE IN OBJECT CODE"
Snit defines the following commands for use in your object code:
that is, for use in type methods, instance methods, constructors,
destructors, onconfigure handlers, oncget handlers, and procs\&.
They do not reside in the ::snit:: namespace; instead, they are
created with the type, and can be used without qualification\&.
.TP
\fBmymethod\fR \fIname\fR ?\fIargs\&.\&.\&.\fR?
The \fBmymethod\fR command is used for formatting callback commands to
be passed to other objects\&.  It returns a command that when called
will invoke method \fIname\fR with the specified arguments, plus of
course any arguments added by the caller\&.  In other words, both of the
following commands will cause the object's
\fBdosomething\fR method to be called when the \fB$button\fR is pressed:
.CS

    $button configure -command [list $self dosomething myargument]

    $button configure -command [mymethod dosomething myargument]

.CE
.IP
The chief distinction between the two is that the latter form will not
break if the object's command is renamed\&.
.TP
\fBmytypemethod\fR \fIname\fR ?\fIargs\&.\&.\&.\fR?
The \fBmytypemethod\fR command is used for formatting callback commands to
be passed to other objects\&.  It returns a command that when called
will invoke type method \fIname\fR with the specified arguments, plus of
course any arguments added by the caller\&.  In other words, both of the
following commands will cause the object's \fBdosomething\fR type method
to be called when \fB$button\fR is pressed:
.CS

    $button configure -command [list $type dosomething myargument]

    $button configure -command [mytypemethod dosomething myargument]

.CE
.IP
Type commands cannot be renamed, so in practice there's little
difference between the two forms\&.  \fBmytypemethod\fR is provided for
parallelism with \fBmymethod\fR\&.
.TP
\fBmyproc\fR \fIname\fR ?\fIargs\&.\&.\&.\fR?
The \fBmyproc\fR command is used for formatting callback commands to
be passed to other objects\&.  It returns a command that when called
will invoke the type proc \fIname\fR with the specified arguments, plus of
course any arguments added by the caller\&.  In other words, both of the
following commands will cause the object's \fBdosomething\fR proc
to be called when \fB$button\fR is pressed:
.CS

    $button configure -command [list ${type}::dosomething myargument]

    $button configure -command [myproc dosomething myargument]

.CE
.TP
\fBmyvar\fR \fIname\fR
Given an instance variable name, returns the fully qualified name\&.
Use this if you're passing the variable to some other object, e\&.g\&., as
a \fB-textvariable\fR to a Tk label widget\&.
.TP
\fBmytypevar\fR \fIname\fR
Given an type variable name, returns the fully qualified name\&.  Use
this if you're passing the variable to some other object, e\&.g\&., as a
\fB-textvariable\fR to a Tk label widget\&.
.TP
\fBfrom\fR \fIargvName\fR \fIoption\fR ?\fIdefvalue\fR?
The \fBfrom\fR command plucks an option value from a list of options
and their values, such as is passed into a type's \fBconstructor\fR\&.
\fIargvName\fR must be the name of a variable containing such a list;
\fIoption\fR is the name of the specific option\&.
.sp
\fBfrom\fR looks for \fIoption\fR in the option list\&.  If it is found,
it and its value are removed from the list, and the value is returned\&.
If \fIoption\fR doesn't appear in the list, then the \fIdefvalue\fR is
returned\&.
If the option is locally-defined option, and \fIdefvalue\fR is
not specified, then the option's default value as specified in the
type definition will be returned instead\&.
.TP
\fBinstall\fR \fIcompName\fR \fBusing\fR \fIobjType\fR \fIobjName\fR \fIargs\&.\&.\&.\fR
Creates a new object of type \fIobjType\fR called \fIobjName\fR
and installs it as component \fIcompName\fR,
as described in \fBComponents and Delegation\fR\&.  Any additional
\fIargs\&.\&.\&.\fR are passed along with the name to the \fIobjType\fR
command\&.
If this is a \fBsnit::type\fR, then the following two commands are
equivalent:
.CS

    install myComp using myObjType $self\&.myComp args\&.\&.\&.

    set myComp [myObjType $self\&.myComp args\&.\&.\&.]

.CE
.IP
Note that whichever method is used, \fIcompName\fR must still be
declared in the type definition using \fBcomponent\fR, or must be
referenced in at least one \fBdelegate\fR statement\&.
.sp
If this is a \fBsnit::widget\fR or \fBsnit::widgetadaptor\fR, and if
options have been delegated to component \fIcompName\fR, then those
options will receive default values from the Tk option database\&.  Note
that it doesn't matter whether the component to be installed is a
widget or not\&.  See \fBThe Tk Option Database\fR for more
information\&.
.sp
\fBinstall\fR cannot be used to install type components; just assign
the type component's command name to the type component's variable
instead\&.
.TP
\fBinstallhull\fR \fBusing\fR \fIwidgetType\fR \fIargs\&.\&.\&.\fR
.TP
\fBinstallhull\fR \fIname\fR
The constructor of a \fBsnit::widgetadaptor\fR must create a widget to
be the object's hull component; the widget is installed as the hull
component using this command\&.  Note that the installed widget's name
must be \fB$win\fR\&.
This command has two forms\&.
.sp
The first form specifies the \fIwidgetType\fR and the \fIargs\&.\&.\&.\fR
(that is, the hardcoded option list) to use in creating the hull\&.
Given this form, \fBinstallhull\fR creates the hull widget, and
initializes any options delegated to the hull from the Tk option
database\&.
.sp
In the second form, the hull widget has already been created; note
that its name must be "$win"\&.  In this case, the Tk option database is
\fInot\fR queried for any options delegated to the hull\&.
The longer form is preferred; however, the shorter form allows the
programmer to adapt a widget created elsewhere, which is sometimes
useful\&.  For example, it can be used to adapt a "page" widget created
by a \fBBWidgets\fR tabbed notebook or pages manager widget\&.
.sp
See \fBThe Tk Option Database\fR for more information
about \fBsnit::widgetadaptor\fRs and the option database\&.
.TP
\fBvariable\fR \fIname\fR
Normally, instance variables are defined in the type definition along
with the options, methods, and so forth; such instance variables are
automatically visible in all instance code (e\&.g\&., method bodies)\&.  However,
instance code can use the \fBvariable\fR command to declare instance variables
that don't appear in the type definition, and also to bring variables
from other namespaces into scope in the usual way\&.
.sp
It's generally clearest to define all instance variables in the type
definition, and omit declaring them in methods and so forth\&.
.sp
Note that this is an instance-specific version of the standard Tcl
\fB::variable\fR command\&.
.TP
\fBtypevariable\fR \fIname\fR
Normally, type variables are defined in the type definition, along
with the instance variables; such type variables are automatically
visible in all of the type's code\&.  However, type methods, instance
methods and so forth can use \fBtypevariable\fR to declare type
variables that don't appear in the type definition\&.
.sp
It's generally clearest to declare all type variables in the type
definition, and omit declaring them in methods, type methods, etc\&.
.TP
\fBvarname\fR \fIname\fR
\fBDeprecated\&.\fR  Use \fBmyvar\fR instead\&.
.sp
Given an instance variable name, returns the fully qualified name\&.
Use this if you're passing the variable to some other object, e\&.g\&., as
a \fB-textvariable\fR to a Tk label widget\&.
.TP
\fBtypevarname\fR \fIname\fR
\fBDeprecated\&.\fR  Use \fBmytypevar\fR instead\&.
.sp
Given a type variable name, returns the fully qualified name\&.  Use
this if you're passing the type variable to some other object, e\&.g\&., as a
\fB-textvariable\fR to a Tk label widget\&.
.TP
\fBcodename\fR \fIname\fR
\fBDeprecated\&.\fR  Use \fBmyproc\fR instead\&.
Given the name of a proc (but not a type or instance method), returns
the fully-qualified command name, suitable for passing as a callback\&.
.PP
.PP
.SS "COMPONENTS AND DELEGATION"
When an object includes other objects, as when a toolbar contains
buttons or a GUI object contains an object that references a database,
the included object is called a component\&.  The standard way to handle
component objects owned by a Snit object is to declare them using
\fBcomponent\fR, which creates a component instance variable\&.
In the following example, a \fBdog\fR object has a
\fBtail\fR object:
.PP
.CS

    snit::type dog {
        component mytail

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

        method wag {} {
            $mytail wag
        }
    }

    snit::type tail {
        option -length 5
        option -partof
        method wag {} { return "Wag, wag, wag\&."}
    }

.CE
.PP
Because the \fBtail\fR object's name is stored in an instance
variable, it's easily accessible in any method\&.
.PP
The \fBinstall\fR command provides an alternate way
to create and install the component:
.PP
.CS

    snit::type dog {
        component mytail

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

        method wag {} {
            $mytail wag
        }
    }

.CE
.PP
For \fBsnit::type\fRs, the two methods are equivalent; for
\fBsnit::widget\fRs and \fBsnit::widgetadaptor\fRs, the \fBinstall\fR
command properly initializes the widget's options by querying
\fBThe Tk Option Database\fR\&.
.PP
In the above examples, the \fBdog\fR object's \fBwag\fR method
simply calls the \fBtail\fR component's \fBwag\fR method\&.  In OO
jargon, this is called delegation\&.  Snit provides an easier way to do
this:
.PP
.CS

    snit::type dog {
        delegate method wag to mytail

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

.CE
.PP
The \fBdelegate\fR statement in the type definition implicitly defines
the instance variable \fBmytail\fR to hold the component's name
(though it's good form to use \fBcomponent\fR to declare it explicitly); it
also defines the \fBdog\fR object's \fBwag\fR method, delegating it
to the \fBmytail\fR component\&.
.PP
If desired, all otherwise unknown methods can be delegated to a
specific component:
.PP
.CS


    snit::type dog {
	delegate method * to mytail

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

	method bark { return "Bark, bark, bark!" }
    }

.CE
.PP
In this case, a \fBdog\fR object will handle its own \fBbark\fR
method; but \fBwag\fR will be passed along to \fBmytail\fR\&.  Any
other method, being recognized by neither \fBdog\fR nor \fBtail\fR,
will simply raise an error\&.
.PP
Option delegation is similar to method delegation, except for the
interactions with the Tk option database; this is described in
\fBThe Tk Option Database\fR\&.
.SS "TYPE COMPONENTS AND DELEGATION"
The relationship between type components and instance components is
identical to that between type variables and instance variables, and
that between type methods and instance methods\&.  Just as an instance
component is an instance variable that holds the name of a command, so
a type component is a type variable that holds the name of a command\&.
In essence, a type component is a component that's shared by every
instance of the type\&.
.PP
Just as \fBdelegate method\fR can be used to delegate methods to
instance components, as described in
\fBComponents and Delegation\fR, so \fBdelegate typemethod\fR
can be used to delegate type methods to type components\&.
.PP
Note also that as of Snit 0\&.95 \fBdelegate method\fR can delegate
methods to both instance components and type components\&.
.SS "THE TK OPTION DATABASE"
This section describes how Snit interacts with the Tk option database,
and assumes the reader has a working knowledge of the option database
and its uses\&.  The book \fIPractical Programming in Tcl and Tk\fR
by Welch et al has a good introduction to the option database, as does
\fIEffective Tcl/Tk Programming\fR\&.
.PP
Snit is implemented so that most of the time it will simply do the
right thing with respect to the option database, provided that the
widget developer does the right thing by Snit\&.  The body of this
section goes into great deal about what Snit requires\&.  The following
is a brief statement of the requirements, for reference\&.
.PP
.IP \(bu
If the \fBsnit::widget\fR's default widget class is not what is desired, set it
explicitly using \fBwidgetclass\fR in the widget definition\&.
.IP \(bu
When defining or delegating options, specify the resource and class
names explicitly when if the defaults aren't what you want\&.
.IP \(bu
Use \fBinstallhull using\fR to install the hull for
\fBsnit::widgetadaptor\fRs\&.
.IP \(bu
Use \fBinstall\fR to install all other components\&.
.PP
.PP
The interaction of Tk widgets with the option database is a complex
thing; the interaction of Snit with the option database is even more
so, and repays attention to detail\&.
.PP
\fBSetting the widget class:\fR Every Tk widget has a widget class\&.
For Tk widgets, the widget class name is the just the widget type name
with an initial capital letter, e\&.g\&., the widget class for
\fBbutton\fR widgets is "Button"\&.
.PP
Similarly, the widget class of a \fBsnit::widget\fR defaults to the
unqualified type name with the first letter capitalized\&.  For example,
the widget class of
.PP
.CS

    snit::widget ::mylibrary::scrolledText { \&.\&.\&. }
.CE
.PP
is "ScrolledText"\&.  The widget class can also be set explicitly using
the \fBwidgetclass\fR statement within the \fBsnit::widget\fR
definition\&.
.PP
Any widget can be used as the \fBhulltype\fR provided that it supports
the \fB-class\fR option for changing its widget class name\&.  See
the discussion of the \fBhulltype\fR command, above\&.  The user may pass
\fB-class\fR to the widget at instantion\&.
.PP
The widget class of a \fBsnit::widgetadaptor\fR is just the widget
class of its hull widget; this cannot be changed unless the hull
widget supports \fB-class\fR, in which case it will
usually make more sense to use \fBsnit::widget\fR rather than
\fBsnit::widgetadaptor\fR\&.
.PP
\fBSetting option resource names and classes:\fR In Tk, every
option has three names: the option name, the resource name, and the
class name\&.  The option name begins with a hyphen and is all lowercase;
it's used when creating widgets, and with the \fBconfigure\fR and
\fBcget\fR commands\&.
.PP
The resource and class names are used to initialize option default
values by querying the Tk option database\&.  The resource name is
usually just the option name minus the hyphen, but may contain
uppercase letters at word boundaries; the class name is usually just
the resource name with an initial capital, but not always\&.  For
example, here are the option, resource, and class names for several
\fBtext\fR widget options:
.PP
.CS

    -background         background         Background
    -borderwidth        borderWidth        BorderWidth
    -insertborderwidth  insertBorderWidth  BorderWidth
    -padx               padX               Pad

.CE
.PP
As is easily seen, sometimes the resource and class names can be
inferred from the option name, but not always\&.
.PP
Snit options also have a resource name and a class name\&.  By default,
these names follow the rule given above: the resource name is the
option name without the hyphen, and the class name is the resource
name with an initial capital\&.  This is true for both locally-defined
options and explicitly delegated options:
.PP
.CS

    snit::widget mywidget {
        option -background
        delegate option -borderwidth to hull
        delegate option * to text
	# \&.\&.\&.
    }

.CE
.PP
In this case, the widget class name is "Mywidget"\&.  The widget has the
following options: \fB-background\fR, which is locally defined, and
\fB-borderwidth\fR, which is explicitly delegated; all other widgets are
delegated to a component called "text", which is probably a Tk
\fBtext\fR widget\&.  If so, \fBmywidget\fR has all the same options as
a \fBtext\fR widget\&.  The option, resource, and class names are as
follows:
.PP
.CS

    -background  background  Background
    -borderwidth borderwidth Borderwidth
    -padx        padX        Pad

.CE
.PP
Note that the locally defined option, \fB-background\fR, happens to have
the same three names as the standard Tk \fB-background\fR option; and
\fB-pad\fR, which is delegated implicitly to the \fBtext\fR
component, has the
same three names for \fBmywidget\fR as it does for the \fBtext\fR
widget\&.  \fB-borderwidth\fR, on the other hand, has different resource and
class names than usual, because the internal word "width" isn't
capitalized\&.  For consistency, it should be; this is done as follows:
.PP
.CS

    snit::widget mywidget {
	option -background
	delegate option {-borderwidth borderWidth} to hull
	delegate option * to text
	# \&.\&.\&.
    }

.CE
.PP
The class name will default to "BorderWidth", as expected\&.
.PP
Suppose, however, that \fBmywidget\fR also delegated
\fB-padx\fR and
\fB-pady\fR to the hull\&.  In this case, both the resource name and the
class name must be specified explicitly:
.PP
.CS

    snit::widget mywidget {
	option -background
	delegate option {-borderwidth borderWidth} to hull
	delegate option {-padx padX Pad} to hull
	delegate option {-pady padY Pad} to hull
	delegate option * to text
	# \&.\&.\&.
    }

.CE
.PP
\fBQuerying the option database:\fR If you set your widgetclass and
option names as described above, Snit will query the option database
when each instance is created, and will generally do the right thing
when it comes to querying the option database\&.  The remainder of this
section goes into the gory details\&.
.PP
\fBInitializing locally defined options:\fR
When an instance of a snit::widget is created, its locally defined
options are initialized as follows: each option's resource and class
names are used to query the Tk option database\&.  If the result is
non-empty, it is used as the option's default; otherwise, the default
hardcoded in the type definition is used\&.  In either case, the default
can be overridden by the caller\&.  For example,
.PP
.CS

    option add *Mywidget\&.texture pebbled

    snit::widget mywidget {
	option -texture smooth
	# \&.\&.\&.
    }

    mywidget \&.mywidget -texture greasy

.CE
.PP
Here, \fB-texture\fR would normally default to "smooth", but because of
the entry added to the option database it defaults to "pebbled"\&.
However, the caller has explicitly overridden the default, and so the
new widget will be "greasy"\&.
.PP
\fBInitializing options delegated to the hull:\fR
A \fBsnit::widget\fR's hull is a widget, and given that its class has
been set it is expected to query the option database for itself\&.  The
only exception concerns options that are delegated to it with a
different name\&.  Consider the following code:
.PP
.CS

    option add *Mywidget\&.borderWidth 5
    option add *Mywidget\&.relief sunken
    option add *Mywidget\&.hullbackground red
    option add *Mywidget\&.background green

    snit::widget mywidget {
	delegate option -borderwidth to hull
	delegate option -hullbackground to hull as -background
	delegate option * to hull
	# \&.\&.\&.
    }

    mywidget \&.mywidget

    set A [\&.mywidget cget -relief]
    set B [\&.mywidget cget -hullbackground]
    set C [\&.mywidget cget -background]
    set D [\&.mywidget cget -borderwidth]

.CE
.PP
The question is, what are the values of variables A, B, C and D?
.PP
The value of A is "sunken"\&.  The hull is a Tk frame that has been
given the widget class "Mywidget"; it will automatically query the
option database and pick up this value\&.  Since the \fB-relief\fR
option is implicitly delegated to the hull, Snit takes no action\&.
.PP
The value of B is "red"\&.  The hull will automatically pick up the
value "green" for its \fB-background\fR option, just as it picked up the
\fB-relief\fR value\&.  However, Snit knows that
\fB-hullbackground\fR is mapped to
the hull's \fB-background\fR option; hence, it queries the option database
for \fB-hullbackground\fR and gets "red" and updates the hull
accordingly\&.
.PP
The value of C is also "red", because \fB-background\fR is implicitly
delegated to the hull; thus, retrieving it is the same as retrieving
\fB-hullbackground\fR\&.  Note that this case is unusual; in practice,
\fB-background\fR would probably be explicitly delegated to some other
component\&.
.PP
The value of D is "5", but not for the reason you think\&.  Note that as
it is defined above, the resource name for \fB-borderwidth\fR
defaults to "borderwidth", whereas the option database entry is
"borderWidth"\&.  As with \fB-relief\fR, the hull picks up its
own \fB-borderwidth\fR option before Snit does anything\&.  Because the
option is delegated under its own name, Snit assumes that the correct
thing has happened, and doesn't worry about it any further\&.
.PP
For \fBsnit::widgetadaptor\fRs, the case is somewhat altered\&.  Widget
adaptors retain the widget class of their hull, and the hull is not
created automatically by Snit\&.  Instead, the \fBsnit::widgetadaptor\fR
must call \fBinstallhull\fR in its constructor\&.  The normal way to do
this is as follows:
.PP
.CS

    snit::widgetadaptor mywidget {
	# \&.\&.\&.
	constructor {args} {
	    # \&.\&.\&.
	    installhull using text -foreground white
	    #
	}
	#\&.\&.\&.
    }

.CE
.PP
In this case, the \fBinstallhull\fR command will create the hull using
a command like this:
.PP
.CS

    set hull [text $win -foreground white]

.CE
.PP
The hull is a \fBtext\fR widget, so its widget class is "Text"\&.  Just
as with \fBsnit::widget\fR hulls, Snit assumes that it will pick up
all of its normal option values automatically; options delegated from
a different name are initialized from the option database in the same
way\&.
.PP
\fBInitializing options delegated to other components:\fR
Non-hull components are matched against the option database in two
ways\&.  First, a component widget remains a widget still, and therefore
is initialized from the option database in the usual way\&.
Second, the option database is queried for all options delegated to
the component, and the component is initialized accordingly--provided
that the \fBinstall\fR command is used to create it\&.
.PP
Before option database support was added to Snit, the usual way to
create a component was to simply create it in the constructor and
assign its command name to the component variable:
.PP
.CS

    snit::widget mywidget {
	delegate option -background to myComp

	constructor {args} {
	    set myComp [text $win\&.text -foreground black]
	}
    }

.CE
.PP
The drawback of this method is that Snit has no opportunity to
initialize the component properly\&.  Hence, the following approach is
now used:
.PP
.CS

    snit::widget mywidget {
	delegate option -background to myComp

	constructor {args} {
	    install myComp using text $win\&.text -foreground black
	}
    }

.CE
.PP
The \fBinstall\fR command does the following:
.PP
.IP \(bu
Builds a list of the options explicitly included in the \fBinstall\fR
command -- in this case, \fB-foreground\fR\&.
.IP \(bu
Queries the option database for all options delegated explicitly to
the named component\&.
.IP \(bu
Creates the component using the specified command, after inserting
into it a list of options and values read from the option database\&.
Thus, the explicitly included options (\fB-foreground\fR) will override
anything read from the option database\&.
.IP \(bu
If the widget definition implicitly delegated options to the component
using \fBdelegate option *\fR, then Snit calls the newly created
component's \fBconfigure\fR method to receive a list of all of the
component's options\&.  From this Snit builds a list of options
implicitly delegated to the component that were not explicitly
included in the \fBinstall\fR command\&.  For all such options, Snit
queries the option database and configures the component accordingly\&.
.PP
.PP
\fBNon-widget components:\fR The option database is never queried
for \fBsnit::type\fRs, since it can only be queried given a Tk widget
name\&.
However, \fBsnit::widget\fRs can have non-widget components\&.  And if
options are delegated to those components, and if the \fBinstall\fR
command is used to install those components, then they will be
initialized from the option database just as widget components are\&.
.PP
.SS "MACROS AND META-PROGRAMMING"
The \fBsnit::macro\fR command enables a certain amount of
meta-programming with Snit classes\&.  For example, suppose you like to
define properties: instance variables that have set/get methods\&.  Your
code might look like this:
.CS

    snit::type dog {
        variable mood happy

        method getmood {} {
            return $mood
        }

        method setmood {newmood} {
            set mood $newmood
        }
    }

.CE
That's nine lines of text per property\&.  Or, you could define the
following \fBsnit::macro\fR:
.CS

    snit::macro property {name initValue} {
        variable $name $initValue

        method get$name {} "return $name"

        method set$name {value} "set $name \\$value"
    }

.CE
Note that a \fBsnit::macro\fR is just a normal Tcl proc defined in
the slave interpreter used to compile type and widget definitions; as
a result, it has access to all the commands used to define types and
widgets\&.
.PP
Given this new macro, you can define a property in one line of code:
.CS

    snit::type dog {
        property mood happy
    }

.CE
Within a macro, the commands \fBvariable\fR and \fBproc\fR refer to
the Snit type-definition commands, not the standard Tcl commands\&.  To
get the standard Tcl commands, use \fB_variable\fR and \fB_proc\fR\&.
.PP
Because a single slave interpreter is used for compiling all Snit
types and widgets in the application, there's the possibility of macro
name collisions\&.  If you're writing a reuseable package using Snit,
and you use some \fBsnit::macro\fRs, define them in your package
namespace:
.CS

    snit::macro mypkg::property {name initValue} { \&.\&.\&. }

    snit::type dog {
        mypkg::property mood happy
    }

.CE
This leaves the global namespace open for application authors\&.
.PP
.SS "VALIDATION TYPES"
A validation type is an object that can be used to validate
Tcl values of a particular kind\&.  For example,
\fBsnit::integer\fR is used to validate that a Tcl value is
an integer\&.
.PP
Every validation type has a \fBvalidate\fR method which is used to
do the validation\&. This method must take a single argument, the value
to be validated; further, it must do nothing if the value is valid,
but throw an error if the value is invalid:
.CS

    snit::integer validate 5     ;# Does nothing
    snit::integer validate 5\&.0   ;# Throws an error (not an integer!)

.CE
.PP
The \fBvalidate\fR method will always return the validated value on success,
and throw the \fB-errorcode\fR INVALID on error\&.
.PP
Snit defines a family of validation types, all of which are
implemented as \fBsnit::type\fR's\&.  They can be used as is;
in addition, their instances serve as parameterized
subtypes\&.  For example, a probability is a number between 0\&.0 and 1\&.0
inclusive:
.CS

    snit::double probability -min 0\&.0 -max 1\&.0

.CE
The example above creates an instance of \fBsnit::double\fR--a
validation subtype--called
\fBprobability\fR, which can be used to validate probability values:
.CS

    probability validate 0\&.5   ;# Does nothing
    probability validate 7\&.9   ;# Throws an error

.CE
Validation subtypes can be defined explicitly, as in the above
example; when a locally-defined option's \fB-type\fR is specified,
they may also be created on the fly:
.CS

    snit::enum ::dog::breed -values {mutt retriever sheepdog}

    snit::type dog {
        # Define subtypes on the fly\&.\&.\&.
        option -breed -type {
            snit::enum -values {mutt retriever sheepdog}
        }

        # Or use predefined subtypes\&.\&.\&.
        option -breed -type ::dog::breed
    }

.CE
.PP
Any object that has a \fBvalidate\fR method with the semantics
described above can be used as a validation type; see
\fBDefining Validation Types\fR for information on how to define
new ones\&.
.PP
Snit defines the following validation types:
.TP
\fBsnit::boolean\fR \fBvalidate\fR ?\fIvalue\fR?
.TP
\fBsnit::boolean\fR \fIname\fR
Validates Tcl boolean values: 1, 0, \fBon\fR, \fBoff\fR,
\fByes\fR, \fBno\fR, \fBtrue\fR, \fBfalse\fR\&.
It's possible to define subtypes--that is, instances--of
\fBsnit::boolean\fR, but as it has no options there's no reason to do
so\&.
.TP
\fBsnit::double\fR \fBvalidate\fR ?\fIvalue\fR?
.TP
\fBsnit::double\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
Validates floating-point values\&.  Subtypes may be created with the
following options:
.RS
.TP
\fB-min\fR \fImin\fR
Specifies a floating-point minimum bound; a value is invalid if it is strictly
less than \fImin\fR\&.
.TP
\fB-max\fR \fImax\fR
Specifies a floating-point maximum bound; a value is invalid if it is strictly
greater than \fImax\fR\&.
.RE
.TP
\fBsnit::enum\fR \fBvalidate\fR ?\fIvalue\fR?
.TP
\fBsnit::enum\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
Validates that a value comes from an enumerated list\&.  The base
type is of little use by itself, as only subtypes actually have
an enumerated list to validate against\&.  Subtypes may be created
with the following options:
.RS
.TP
\fB-values\fR \fIlist\fR
Specifies a list of valid values\&.  A value is valid if and only if
it's included in the list\&.
.RE
.TP
\fBsnit::fpixels\fR \fBvalidate\fR ?\fIvalue\fR?
.TP
\fBsnit::fpixels\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
\fITk programs only\&.\fR Validates screen distances, in any of the
forms accepted by \fBwinfo fpixels\fR\&. Subtypes may be created with the
following options:
.RS
.TP
\fB-min\fR \fImin\fR
Specifies a minimum bound; a value is invalid if it is strictly
less than \fImin\fR\&.  The bound may be expressed in any of the
forms accepted by \fBwinfo fpixels\fR\&.
.TP
\fB-max\fR \fImax\fR
Specifies a maximum bound; a value is invalid if it is strictly
greater than \fImax\fR\&.  The bound may be expressed in any of the
forms accepted by \fBwinfo fpixels\fR\&.
.RE
.TP
\fBsnit::integer\fR \fBvalidate\fR ?\fIvalue\fR?
.TP
\fBsnit::integer\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
Validates integer values\&.  Subtypes may be created with the
following options:
.RS
.TP
\fB-min\fR \fImin\fR
Specifies an integer minimum bound; a value is invalid if it is strictly
less than \fImin\fR\&.
.TP
\fB-max\fR \fImax\fR
Specifies an integer maximum bound; a value is invalid if it is strictly
greater than \fImax\fR\&.
.RE
.TP
\fBsnit::listtype\fR \fBvalidate\fR ?\fIvalue\fR?
.TP
\fBsnit::listtype\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
Validates Tcl lists\&. Subtypes may be created with the
following options:
.RS
.TP
\fB-minlen\fR \fImin\fR
Specifies a minimum list length; the value is invalid if it has
fewer than \fImin\fR elements\&.  Defaults to 0\&.
.TP
\fB-maxlen\fR \fImax\fR
Specifies a maximum list length; the value is invalid if it
more than \fImax\fR elements\&.
.TP
\fB-type\fR \fItype\fR
Specifies the type of the list elements; \fItype\fR must be
the name of a validation type or subtype\&.  In the
following example, the value of \fB-numbers\fR must be a list
of integers\&.
.CS

    option -numbers -type {snit::listtype -type snit::integer}

.CE
.IP
Note that this option doesn't support defining new validation subtypes
on the fly; that is, the following code will not work (yet, anyway):
.CS

    option -numbers -type {
        snit::listtype -type {snit::integer -min 5}
    }

.CE
.IP
Instead, define the subtype explicitly:
.CS

    snit::integer gt4 -min 5

    snit::type mytype {
        option -numbers -type {snit::listtype -type gt4}
    }

.CE
.RE
.TP
\fBsnit::pixels\fR \fBvalidate\fR ?\fIvalue\fR?
.TP
\fBsnit::pixels\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
\fITk programs only\&.\fR Validates screen distances, in any of the
forms accepted by \fBwinfo pixels\fR\&. Subtypes may be created with the
following options:
.RS
.TP
\fB-min\fR \fImin\fR
Specifies a minimum bound; a value is invalid if it is strictly
less than \fImin\fR\&.  The bound may be expressed in any of the
forms accepted by \fBwinfo pixels\fR\&.
.TP
\fB-max\fR \fImax\fR
Specifies a maximum bound; a value is invalid if it is strictly
greater than \fImax\fR\&.  The bound may be expressed in any of the
forms accepted by \fBwinfo pixels\fR\&.
.RE
.TP
\fBsnit::stringtype\fR \fBvalidate\fR ?\fIvalue\fR?
.TP
\fBsnit::stringtype\fR \fIname\fR ?\fIoption\fR \fIvalue\fR\&.\&.\&.?
Validates Tcl strings\&. The base type is of little use by itself,
since very Tcl value is also a valid string\&.  Subtypes may be created with the
following options:
.RS
.TP
\fB-minlen\fR \fImin\fR
Specifies a minimum string length; the value is invalid if it has
fewer than \fImin\fR characters\&.  Defaults to 0\&.
.TP
\fB-maxlen\fR \fImax\fR
Specifies a maximum string length; the value is invalid if it has
more than \fImax\fR characters\&.
.TP
\fB-glob\fR \fIpattern\fR
Specifies a \fBstring match\fR pattern; the value is invalid
if it doesn't match the pattern\&.
.TP
\fB-regexp\fR \fIregexp\fR
Specifies a regular expression; the value is invalid if it doesn't
match the regular expression\&.
.TP
\fB-nocase\fR \fIflag\fR
By default, both \fB-glob\fR and \fB-regexp\fR matches are
case-sensitive\&.  If \fB-nocase\fR is set to true, then both
\fB-glob\fR and \fB-regexp\fR matches are case-insensitive\&.
.RE
.TP
\fBsnit::window\fR \fBvalidate\fR ?\fIvalue\fR?
.TP
\fBsnit::window\fR \fIname\fR
\fITk programs only\&.\fR  Validates Tk window names\&.  The value must
cause \fBwinfo exists\fR to return true; otherwise, the value is
invalid\&.  It's possible to define subtypes--that is, instances--of
\fBsnit::window\fR, but as it has no options at present there's no
reason to do so\&.
.PP
.PP
.SS "DEFINING VALIDATION TYPES"
There are three ways to define a new validation type: as a subtype of
one of Snit's validation types, as a validation type command, and as
a full-fledged validation type similar to those provided by Snit\&.
Defining subtypes of Snit's validation types is described above,
under \fBValidation Types\fR\&.
.PP
The next simplest way to create a new validation type is as a
validation type command\&.  A validation type is simply an
object that has a \fBvalidate\fR method; the \fBvalidate\fR
method must take one argument, a value, return the value if it is
valid, and throw an error with \fB-errorcode\fR INVALID if the
value is invalid\&.  This can be done with a simple \fBproc\fR\&.  For
example, the \fBsnit::boolean\fR validate type could have been
implemented like this:
.CS

    proc ::snit::boolean {"validate" value} {
        if {![string is boolean -strict $value]} {
            return -code error -errorcode INVALID  "invalid boolean \\"$value\\", should be one of: 1, 0, \&.\&.\&."
        }

        return $value
    }

.CE
A validation type defined in this way cannot be subtyped, of course;
but for many applications this will be sufficient\&.
.PP
Finally, one can define a full-fledged, subtype-able validation type
as a \fBsnit::type\fR\&.  Here's a skeleton to get you started:
.CS

    snit::type myinteger {
        # First, define any options you'd like to use to define
        # subtypes\&.  Give them defaults such that they won't take
        # effect if they aren't used, and marked them "read-only"\&.
        # After all, you shouldn't be changing their values after
        # a subtype is defined\&.
        #
        # For example:

        option -min -default "" -readonly 1
        option -max -default "" -readonly 1

        # Next, define a "validate" type method which should do the
        # validation in the basic case\&.  This will allow the
        # type command to be used as a validation type\&.

        typemethod validate {value} {
            if {![string is integer -strict $value]} {
                return -code error -errorcode INVALID  "invalid value \\"$value\\", expected integer"
            }

            return $value
        }

        # Next, the constructor should validate the subtype options,
        # if any\&.  Since they are all readonly, we don't need to worry
        # about validating the options on change\&.

        constructor {args} {
            # FIRST, get the options
            $self configurelist $args

            # NEXT, validate them\&.

            # I'll leave this to your imagination\&.
        }

        # Next, define a "validate" instance method; its job is to
        # validate values for subtypes\&.

        method validate {value} {
            # First, call the type method to do the basic validation\&.
            $type validate $value

            # Now we know it's a valid integer\&.

            if {("" != $options(-min) && $value < $options(-min))  ||
                ("" != $options(-max) && $value > $options(-max))} {
                # It's out of range; format a detailed message about
                # the error, and throw it\&.

                set msg "\&.\&.\&.\&."

                return -code error -errorcode INVALID $msg
            }

            # Otherwise, if it's valid just return it\&.
            return $valid
        }
    }

.CE
And now you have a type that can be subtyped\&.
.PP
The file "validate\&.tcl" in the Snit distribution defines all of Snit's
validation types; you can find the complete implementation for
\fBsnit::integer\fR and the other types there, to use as examples for
your own types\&.
.PP
.SH CAVEATS
If you have problems, find bugs, or new ideas you are hereby cordially
invited to submit a report of your problem, bug, or idea as explained
in the section \fBBugs, Ideas, Feedback\fR below\&.
.PP
Additionally, you might wish to join the Snit mailing list;
see \fIhttp://www\&.wjduquette\&.com/snit\fR for details\&.
.PP
One particular area to watch is using \fBsnit::widgetadaptor\fR to
adapt megawidgets created by other megawidget packages; correct
widget destruction depends on the order of the <Destroy> bindings\&.
The wisest course is simply not to do this\&.
.SH "KNOWN BUGS"
.IP \(bu
Error stack traces returned by Snit 1\&.x are extremely ugly and typically
contain far too much information about Snit internals\&.  The error
messages are much improved in Snit 2\&.2\&.
.IP \(bu
Also see the Project Trackers as explained in the section
\fBBugs, Ideas, Feedback\fR below\&.
.PP
.SH HISTORY
During the course of developing Notebook
(See \fIhttp://www\&.wjduquette\&.com/notebook\fR), my Tcl-based personal
notebook application, I found I was writing it as a collection of
objects\&.  I wasn't using any particular object-oriented framework; I
was just writing objects in pure Tcl following the guidelines in my
Guide to Object Commands
(see \fIhttp://www\&.wjduquette\&.com/tcl/objects\&.html\fR), along with a
few other tricks I'd picked up since\&.  And though it was working well,
it quickly became tiresome because of the amount of boilerplate
code associated with each new object type\&.
.PP
So that was one thing--tedium is a powerful motivator\&.  But the other
thing I noticed is that I wasn't using inheritance at all, and I
wasn't missing it\&.  Instead, I was using delegation: objects that
created other objects and delegated methods to them\&.
.PP
And I said to myself, "This is getting tedious\&.\&.\&.there has got to be a
better way\&."  And one afternoon, on a whim, I started working on Snit,
an object system that works the way Tcl works\&.  Snit doesn't support
inheritance, but it's great at delegation, and it makes creating
megawidgets easy\&.
.PP
If you have any comments or suggestions (or bug reports!) don't
hesitate to send me e-mail at \fIwill@wjduquette\&.com\fR\&.  In addition,
there's a Snit mailing list; you can find out more about it at the
Snit home page (see \fIhttp://www\&.wjduquette\&.com/snit\fR)\&.
.PP
.SH CREDITS
Snit has been designed and implemented from the very beginning by
William H\&. Duquette\&.  However, much credit belongs to the following
people for using Snit and providing me with valuable feedback: Rolf
Ade, Colin McCormack, Jose Nazario, Jeff Godfrey, Maurice Diamanti,
Egon Pasztor, David S\&. Cargo, Tom Krehbiel, Michael Cleverly,
Andreas Kupries, Marty Backe, Andy Goth, Jeff Hobbs, Brian
Griffin, Donal Fellows, Miguel Sofer, Kenneth Green,
and Anton Kovalenko\&.
If I've forgotten anyone, my apologies; let me know and I'll add
your name to the list\&.
.SH "BUGS, IDEAS, FEEDBACK"
This document, and the package it describes, will undoubtedly contain
bugs and other problems\&.
Please report such in the category \fIsnit\fR of the
\fITcllib Trackers\fR [http://core\&.tcl\&.tk/tcllib/reportlist]\&.
Please also report any ideas for enhancements you may have for either
package and/or documentation\&.
.PP
When proposing code changes, please provide \fIunified diffs\fR,
i\&.e the output of \fBdiff -u\fR\&.
.PP
Note further that \fIattachments\fR are strongly preferred over
inlined patches\&. Attachments can be made by going to the \fBEdit\fR
form of the ticket immediately after its creation, and then using the
left-most button in the secondary navigation bar\&.
.SH KEYWORDS
BWidget, C++, Incr Tcl, Snit, adaptors, class, mega widget, object, object oriented, type, widget, widget adaptors
.SH CATEGORY
Programming tools
.SH COPYRIGHT
.nf
Copyright (c) 2003-2009, by William H\&. Duquette

.fi
