# Snit V0.93 Frequently Asked Questions

### OVERVIEW

- What is this document?
- What is Snit?
- What version of Tcl does Snit require?
- What are Snit's goals?
- How is Snit different from other OO frameworks?
- What can I do with Snit?

### OBJECTS

- What is an object?
- What is an abstract data type?
- What kinds of abstract data types does Snit provide?
- What is a snit::type?
- What is a snit::widget?
- What is a snit::widgetadaptor?
- How do I create an instance of a snit::type?
- How do I refer to an object indirectly?
- How can I generate the object name automatically?
- Can types be renamed?
- Can objects be renamed?
- How do I destroy a Snit object?

### INSTANCE METHODS

- What is an instance method?
- How do I define an instance method?
- How does a client call an instance method?
- How does an instance method call another instance method?
- Are there any limitations on instance method names?
- How do I make an instance method private?
- Are there any limitations on instance method arguments?
- What implicit arguments are passed to each instance method?
- What is $type?
- What is $self?
- What is $selfns?
- What is $win?
- How do I pass an instance method as a callback?
- How do I delegate instance methods to a component?

### INSTANCE VARIABLES

- What is an instance variable?
- How is a scalar instance variable defined?
- How is an array instance variable defined?
- Are there any limitations on instance variable names?
- Do I need to declare instance variables before using them?
- How do I pass an instance variable's name to another object?
- How do I make an instance variable public?

### OPTIONS

- What is an option?
- How do I define an option?
- How can a client set options at object creation?
- How can a client retrieve an option's value?
- How can a client set options after object creation?
- How should an instance method access an option value?
- How can I catch changes to an option's value?
- What is an onconfigure handler?
- How can I catch accesses to an option's value?
- What is an oncget handler?

### TYPE VARIABLES

- What is a type variable?
- How is a scalar type variable defined?
- How is an array type variable defined?
- Are there any limitations on type variable names?
- Do I need to declare type variables before using them?
- How do I pass a type variable's name to another object?
- How do I make a type variable public?

### TYPE METHODS

- What is a type method?
- How do I define a type method?
- How does a client call a type method?
- Are there any limitations on type method names?
- How do I make a type method private?
- Are there any limitations on type method arguments?
- How does an instance or type method call a type method?
- How do I pass a type method as a callback?

### PROCS

- What is a proc?
- How do I define a proc?
- Are there any limitations on proc names?
- How does a method call a proc?
- How can I pass a proc to another object as a callback?

### TYPE CONSTRUCTORS

- What is a type constructor?
- How do I define a type constructor?

### CONSTRUCTORS

- What is a constructor?
- How do I define a constructor?
- What does the default constructor do?
- Can I choose a different command line syntax for the constructor?
- Are there any limitations on constructor arguments?
- What implicit arguments are passed to the constructor?

### DESTRUCTORS

- What is a destructor?
- How do I define a destructor?
- Are there any limitations on destructor arguments?
- What implicit arguments are passed to the destructor?
- Must components be destroyed explicitly?

### COMPONENTS

- What is a component?
- How do I create a component?
- How is a component named?
- What does the install command do?
- Are there any limitations on component names?
- Are there any limitations on component object names?
- Must I destroy the components I create?
- Can I expose a component's object command as part of my interface?
- How do I expose a component's object command?

### DELEGATION

- What is delegation?
- How can I delegate a method to a component object?
- Can I delegate to a method with a different name?
- Can I delegate to a method with additional arguments?
- How can I delegate an option to a component object?
- Can I delegate to an option with a different name?
- How can I delegate any unrecognized method or option to a component object?
- How can I delegate all but certain methods or options to a component?

### WIDGETS

- What is a snit::widget?
- How do I define a snit::widget?
- How do snit::widgets differ from snit::types?
- What is a hull component?
- How can I set the hull type for a snit::widget?
- How should I name widgets which are components of a snit::widget?

### WIDGETADAPTORS

- What is a snit::widgetadaptor?
- How do I define a snit::widgetadaptor?
- Can I adapt a widget created by someone else?

### THE TK OPTION DATABASE

- What is the Tk option database?
- Do snit::types use the Tk option database?
- What is my snit::widget's widget class?
- What is my snit::widgetadaptor's widget class?
- What are option resource and class names?
- What are the resource and class names for my megawidget's options?
- How does Snit initialize my megawidget's locally-defined options?
- How does Snit initialize delegated options?
- How does Snit initialize options delegated to the hull?
- How does Snit initialize options delegated to other components?
- What happens if I install a non-widget as a component of widget?

## OVERVIEW

#### What is this document?

This is an atypical FAQ list, in that few of the questions are frequently asked. Rather, these are the questions I think a newcomer to Snit should be asking. This file is not a complete reference to Snit, however; that information is in the Snit man page.

#### What is Snit?

Snit is a framework for defining abstract data types and megawidgets in pure Tcl. The name stands for "Snit's Not Incr Tcl", signifying that Snit takes a different approach to defining objects than does Incr Tcl, the best known object framework for Tcl.

#### What version of Tcl does Snit require?

Snit requires version Tcl 8.4 or later.

#### What are Snit's goals?

In developing Snit I had the following goals:

- It should be at least as efficient as the object code I'd been writing by hand.

- The fact that Snit was used in an object's implementation should be transparent (and irrelevant) to clients of that object.

- Snit should be able to encapsulate objects from other sources, particularly Tk widgets.

- Snit megawidgets should be (to the extent possible) indistinguishable in interface from Tk widgets.

- Snit should be Tclish--that is, rather than trying to emulate C++, Smalltalk, or anything else, it should try to emulate Tcl itself.

- It should have a simple, easy-to-use, easy-to-remember syntax.

#### How is Snit different from other OO frameworks?

Snit is unique among Tcl object systems (so far as I know) in that it's a system based not on inheritance but on delegation. Object systems based on inheritance only allow you to inherit from classes defined using the same system, and that's a shame. In Tcl, an object is anything that acts like an object; it shouldn't matter how the object was implemented. I designed Snit to help me 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 Tk widget, an Incr Tcl object, a BWidget or almost anything else.

#### What can I do with Snit?

Using Snit, a programmer can:

- Create abstract data types and Tk megawidgets.

- Define instance variables, type variables, and option variables.

- Define constructors, destructors, instance methods, type methods, and several kinds of handler.

- Assemble a type out of component types. Instance methods and options can be delegated to the component types automatically.

## OBJECTS

#### What is an object?

Obviously, a full description of object-oriented programming is beyond the scope of this FAQ. In simple terms, an object is an instance of an abstract data type--a coherent bundle of code and data. There are many ways to represent objects in Tcl/Tk; the best known example are the Tk widgets. A widget is an object; it is represented by a Tcl command. The object's methods are subcommands of the Tcl command. Snit uses the same conventions as Tk widgets do.

#### What is an abstract data type?

In computer science terms, an abstract data type is a complex data structure along with a set of operations, like a stack, a queue, or a binary tree--that is to say, in modern terms, an object. In systems that include include some form of inheritance the word "class" is usually used instead of "abstract data type", but as Snit doesn't do inheritance, the older term seems more appropriate. Sometimes this is called object-based programming as opposed to object-oriented programming.

In Snit, as in Tk, a type is a command that creates instances--objects--that belong to the type. Most types define some number of "options" that can be set at creation time, and usually can be changed later.

Further, an instance is also a Tcl command--a command that gives access to the operations that are defined for that abstract data type. Conventionally, the operations are defined as subcommands, or instance methods of the instance command. For example, to insert text into a Tk text widget, you use the text widget's "insert" method:

        # Create a text widget and insert some text in it.
        text .mytext -width 80 -height 24
        .mytext insert end "Howdy!"

In this example, "text" is the type command and ".mytext" is the instance command.

#### What kinds of abstract data types does Snit provide?

Snit allows you to define three kinds of abstract data types:

- `snit::type`
- `snit::widget`
- `snit::widgetadaptor`

#### What is a snit::type?

A `snit::type` is a non-GUI abstract data type, e.g., a stack or a queue. `snit::types` are defined using the `snit::type` command. For example, if you were designing a kennel management system for a dog breeder, you'd need a dog type.

    % snit::type dog {
        # ...
    }
    ::dog
    %

This definition defines a new command (`::dog`, in this case) that can be used to define dog objects.

An instance of a `snit::type` can have instance methods, instance variables, options, and components. The type itself can have type methods and procs.

#### What is a snit::widget?

A `snit::widget` is a Tk megawidget built using Snit; it is very similar to a `snit::type`. See WIDGETS.

#### What is a snit::widgetadaptor?

A `snit::widgetadaptor` uses Snit to wrap an existing widget type (e.g., a Tk label), modifying its interface to a lesser or greater extent. It is very similar to a `snit::widget`. See WIDGETADAPTORS.

#### How do I create an instance of a snit::type?

You create an instance of a `snit::type` by passing the new instance's name to the type's create method. In the following example, we create a `dog` object called `spot`.

    % snit::type dog {
        # ....
    }
    ::dog
    % dog create spot
    ::spot
    %

The "create" method name can be omitted so long as the instance name doesn't conflict with any defined type methods. So the following example is identical to the previous example:

    % snit::type dog {
        # ....
    }
    ::dog
    % dog spot
    ::spot
    %

This document generally uses the shorter form.

If the `dog` type defines options, these can be given defaults at creation time:

    % snit::type dog {
        option -breed mongrel
        option -color brown

        method bark {} { return "$self barks." }
    }
    ::dog
    % dog create spot -breed dalmation -color spotted
    ::spot
    % spot cget -breed
    dalmation
    % spot cget -color
    spotted
    %

Either way, the instance name now names a new Tcl command that is used to manipulate the object. For example, the following code makes the dog bark:

    % spot bark
    ::spot barks.
    %

#### How do I refer to an object indirectly?

Some programmers prefer to save the object name in a variable, and reference it that way. For example,

    % snit::type dog {
        option -breed mongrel
        option -color brown

        method bark {} { return "$self barks." }
    }
    ::dog
    % set d [dog spot -breed dalmation -color spotted]
    ::spot
    % $d cget -breed
    dalmation
    % $d bark
    ::spot barks.
    %

#### How can I generate the object name automatically?

If you'd like Snit to generate an object name for you, use the "%AUTO%" keyword as the requested name:

    % snit::type dog {
        method bark {} { return "$self barks." }
    }
    ::dog
    % set d [dog %AUTO%]
    ::dog2
    % $d bark
    ::dog2 barks.
    %

The "%AUTO%" keyword can be embedded in a longer string:

    % set d [dog dog%AUTO%]
    ::dogdog5
    % $d bark
    ::dogdog5 barks.
    %

#### Can types be renamed?

Tcl's "`rename`" command renames other commands. It's a common technique in Tcl to modify an existing command by renaming it and defining a new command with the original name; the new command usually calls the renamed command.

`snit::type`'s, however, should never be renamed; to do so breaks the connection between the type and its objects.

#### Can objects be renamed?

Tcl's "`rename`" command renames other commands. It's a common technique in Tcl to modify an existing command by renaming it and defining a new command with the original name; the new command usually calls the renamed command.

All Snit objects (including widgets and widgetadaptors) can be renamed, though this flexibility has some consequences:

- In an instance method, $self will always contain the object's current name, so instance methods can always call other instance methods using $self.

- If the object is renamed, however, then $self's value will change. Therefore, don't use $self for anything that will break if $self changes. For example, don't pass a callback command to another object like this:

      [list $self methodname args...]

  You'll get an error if this command is called after your object is renamed.

- Instead, the object should pass the callback command like this:

      [mymethod methodname args...]

  The `mymethod` command returns code that will call the desired method safely; the caller of the callback can safely add additional arguments to the end of the command as usual.

  For example, one could use this code to call a method when a Tk button is pushed:

      .btn configure -command [list $self buttonpress]

  This will break if your instance is renamed. Here's the safe way to do it:

      .btn configure -command [mymethod buttonpress]

- Every object has a private namespace; the name of this namespace is available in method bodies, etc., as "$selfns". This value is constant for the life the object. Use "$selfns" instead of "$self" if you need a unique token to identify the object.

- When a snit::widget's instance command is renamed, its Tk window name remains the same--and is still extremely important. Consequently, the Tk window name is available in `snit::widget` method bodies, etc., as "$win". This value is constant for the life of the object. When creating child windows, it's best to use "$win.child" rather than "$self.child" as the name of the child window.

- The names "selfns" and "win" may not be used as explicit argument names for typemethods, methods, constructors, or onconfigure handlers.

- procs defined in a Snit type or widget definition used to be able to reference instance variables if "$self" was passed to them explicitly as the argument "self"; this is no longer the case.

#### How do I destroy a Snit object?

Every instance of a `snit::type` has a `destroy` method:

    % snit::type dog {
        method bark {} { return "$self barks." }
    }
    ::dog
    % dog spot
    ::spot
    % spot bark
    ::spot barks.
    % spot destroy
    % info commands ::spot
    %

Snit megawidgets (i.e., instances of `snit::widget` and `snit::widgetadaptor`) are destroyed like any other widget: by using the Tk `destroy` command on the widget or on one of its ancestors in the window hierarchy.

In addition, any Snit object of any type can be destroyed by renaming it to "" using the Tcl `rename` command.

## INSTANCE METHODS

#### What is an instance method?

An instance method is a procedure associated with a specific object. It is given free access to all of the object's type variables, instance variables, and so forth.

#### How do I define an instance method?

Instance methods are defined in the type definition using the "method" statement. Consider the following code that might be used to add dogs to a computer simulation:

    % snit::type dog {
        method bark {} {
            return "$self barks."
        }

        method chase {thing} {
            return "$self chases $thing."
        }
    }
    ::dog
    %

A dog can bark, and it can chase things.

The "method" statement looks just like a normal Tcl "proc", except that it appears in a `snit::type` definition. Notice that every instance method gets an implicit argument called "`self`"; this argument contains the object's name.

#### How does a client call an instance method?

The method name becomes a subcommand of the object. For example, let's put a simulated dog through its paces:

    % dog spot
    ::spot
    % spot bark
    ::spot barks.
    % spot chase cat
    ::spot chases cat.
    %

#### How does an instance method call another instance method?

If method A needs to call method B on the same object, it does so just as a client does: it calls method B as a subcommand of the object itself, using the object name stored in "`self`".

Suppose, for example, that our dogs never chase anything without barking at them:

    % snit::type dog {
        method bark {} {
            return "$self barks."
        }

        method chase {thing} {
            return "$self chases $thing.  [$self bark]"
        }
    }
    ::dog
    % dog spot
    ::spot
    % spot bark
    ::spot barks.
    % spot chase cat
    ::spot chases cat.  ::spot barks.
    %

#### Are there any limitations on instance method names?

Not really, so long as you avoid the standard instance method names: `configure`, `configurelist`, `cget`, `destroy`, and `info`.

#### How do I make an instance method private?

It's often useful to define private methods, that is, instance methods intended to be called only by other methods of the same object.

Snit doesn't implement any access control on instance methods, so all methods are de facto public. Conventionally, though, the names of public methods begin with a lower-case letter, and the names of private methods begin with an upper-case letter.

For example, suppose our simulated dogs only bark in response to other stimuli; they never bark just for fun. So the "bark" method could be private:

    % snit::type dog {
        # Private by convention: begins with uppercase letter.
        method Bark {} {
            return "$self barks."
        }

        method chase {thing} {
            return "$self chases $thing. [$self Bark]"
        }
    }
    ::dog
    % dog fido
    ::fido
    % fido chase cat
    ::fido chases cat. ::fido barks.
    %

#### Are there any limitations on instance method arguments?

Method argument lists are defined just like normal Tcl proc argument lists; they can include default values, and the "args" argument. However, every method is called with a number of implicit arguments provided by Snit in addition to those explicitly defined. The names of these implicit arguments may not used to name explicit arguments.

#### What implicit arguments are passed to each instance method?

The arguments implicitly passed to every method are `type`, `selfns`, `win`, and `self`.

#### What is $type?

The implicit argument "`type`" contains the fully qualified name of the object's type:

    % snit::type thing {
        method mytype {} {
            return $type
        }
    }
    ::thing
    % thing something
    ::something
    % something mytype
    ::thing
    %

#### What is $self?

The implicit argument "`self`" contains the object's fully qualified name.

If the object's command is renamed, then "`$self`" will change to match in subsequent calls. Thus, your code should not assume that "`$self`" is constant unless you know for sure that the object will never be renamed.

    % snit::type thing {
        method myself {} {
            return $self
        }
    }
    ::thing
    % thing mutt
    ::mutt
    % mutt myself
    ::mutt
    % rename mutt jeff
    % jeff myself
    ::jeff
    %

#### What is $selfns?

Each Snit object has a private namespace in which to store its instance variables and options. The implicit argument "`$selfns`" is the name of this namespace; it never changes, and is constant for the life of the object, even if the object's name changes:

    % snit::type thing {
        method myNameSpace {} {
            return $selfns
        }
    }
    ::thing
    % thing jeff
    ::jeff
    % jeff myNameSpace
    ::thing::Snit_inst3
    % rename jeff mutt
    % mutt myNameSpace
    ::thing::Snit_inst3
    %

The above example reveals how Snit names an instance's private namespace; however, you should not write code that depends on the specific naming convention, as it might change in future releases.

#### What is $win?

The implicit argument "`win`" is defined for all Snit methods, including those of widgets and widgetadaptors, though it makes sense mostly for the latter two kinds. "`$win`" is simply the original name of the object, whether it's been renamed or not. For widgets and widgetadaptors, it is also therefore the name of a Tk window. When a `snit::widgetadaptor` is used to modify the interface of a widget or megawidget, it must rename the widget's original command and replace it with its own. Thus, using "`$win`" whenever the Tk window name is called for means that a `snit::widget` or `snit::widgetadaptor` can be adapted by a `snit::widgetadaptor`. See WIDGETS for more information.

#### How do I pass an instance method as a callback?

It depends on the context. Suppose in my application I have a `dog` object named `fido`, and I want `fido` to bark when a Tk button is pressed. In this case, I pass the instance method in the normal way, as a subcommand of `fido`:

    button .bark -text "Bark!" -command [list fido bark]

In typical Tcl style, we use a callback to hook two independent components together. But what if the `dog` object itself, passing one of its own instance methods to another object (one of its components, say)? The obvious thing to do is this:

    % snit::widget dog {
        constructor {args} {
            #...
            button $win.barkbtn -text "Bark!"  -command [list $self bark]
            #...
        }
    }
    ::dog
    %

(Note that in this example, our `dog` becomes a `snit::widget`, because it has GUI behavior. See WIDGETS for more.) Thus, if we create a `dog` called `.spot`, it will create a Tk button called `.barkbtn` and pass it "`$self bark`" as the command.

Now, this will work--provided that `.spot` is never renamed. But why should `.spot` be renamed? Surely renaming widgets is abnormal? And so it is--unless `.spot` is the hull component of a `snit::widgetadaptor`. If it is, then it will be renamed, and `.spot` will name the `snit::widgetadaptor` object. When the button is pressed, the command "`$self bark`" will be handled by the `snit::widgetadaptor`, which might or might not do the right thing.

There's a safer way to do it, and it looks like this:

    % snit::widget dog {
        constructor {args} {
            #...
            button $win.barkbtn -text "Bark!"  -command [mymethod bark]
            #...
        }
    }
    ::dog
    %

The command `mymethod` can be used like `list` to build up a callback command; the only difference is that `mymethod` returns a form of the command that won't change if the instance's name changes.

#### How do I delegate instance methods to a component?

See DELEGATION.

## INSTANCE VARIABLES

#### What is an instance variable?

An instance variable is a private variable associated with some particular Snit object. Instance variables can be scalars or arrays.

#### How is a scalar instance variable defined?

Scalar instance variables are defined in the type definition using the `variable` statement. You can simply name it, or you can initialize it with a value:

    snit::type mytype {
        # Define variable "greeting" and initialize it with "Howdy!"
        variable greeting "Howdy!"
    }

#### How is an array instance variable defined?

Array instance variables are also defined using the `variable` command; however, you can't initialize them using the variable command. Typically, they get initialized in the constructor:

    snit::type mytype {
        # Define array variable "greetings"
        variable greetings

        constructor {args} {
            set greetings(formal) "Good Evening"
            set greetings(casual) "Howdy!"
        }
    }

#### Are there any limitations on instance variable names?

Just a few.

First, every Snit object has a built-in instance variable called "options", which should never be redefined.

Second, all names beginning with "Snit_" or "snit_" are reserved for use by Snit internal code.

Third, instance variable names with the namespace delimiter ("::") in them are likely to cause great confusion.

#### Do I need to declare instance variables before using them?

No. Once you've defined an instance variable in the type definition, it can be used in any instance code without declaration. This differs from normal Tcl practice, in which all non-local variables in a proc need to be declared.

#### How do I pass an instance variable's name to another object?

In Tk, it's common to pass a widget a variable name; for example, Tk label widgets have a `-textvariable` option which names the variable which will contain the widget's text. This allows the program to update the label's value just by assigning a new value to the variable.

If you naively pass the instance variable name to the label widget, you'll be confused by the result; Tk will assume that the name names a global variable. Instead, you need to provide a fully-qualified variable name. From within an instance method or a constructor, you can fully qualify the variable's name using the `varname` command:

    snit::widget mywidget {
        variable labeltext ""

        constructor {args} {
            # ...

            label $win.label -textvariable [varname labeltext]

            # ...
        }
    }

#### How do I make an instance variable public?

Practically speaking, you don't. Instead, you'll implement public variables as options. Alternatively, you can write instance methods to set and get the variable's value.

## OPTIONS

#### What is an option?

A type's options are the equivalent of what other object-oriented languages would call public member variables or properties: they are data values which can be retrieved and (usually) set by the clients of an object. If a type is to be used a record type, it's possible that options are all that's needed.

Snit's implementation of options follows the Tk model fairly exactly, except that `snit::type` objects can't interact with Tk's option database; `snit::widget` and `snit::widgetadaptor` objects, on the other hand, can and do.

#### How do I define an option?

Options are defined in the type definition using the `option` statement. Consider the following type, to be used in an application that manages a list of dogs for a pet store:

    % snit::type dog {
        option -breed mongrel
        option -color brown
        option -akc 0
        option -shots 0
    }
    ::dog
    %

According to this, a dog has four notable properties, or options: a breed, a color, a flag that says whether it's pedigreed with the American Kennel Club, and another flag that says whether it has had its shots. The default dog, evidently, is a brown mutt.

If no default value is specified, the option's value defaults to the empty string, {}.

The Snit man page refers to these as "locally defined" options.

#### How can a client set options at object creation?

The normal convention is that the client may pass any number of options and their values after the object's name at object creation. For example, the ::dog command defined in the previous answer can now be used to define individual dogs. Any or all of the options may be set at creation time.

    % dog spot -breed beagle -color "mottled" -akc 1 -shots 1
    ::spot
    % dog fido -shots 1
    ::fido
    %

So ::spot is a pedigreed beagle; ::fido is a typical mutt, but his owners evidently take care of him, because he's had his shots.

NOTE: If the type defines a constructor, it can specify a different object-creation syntax. See CONSTRUCTORS for more information.

#### How can a client retrieve an option's value?

Retrieve option values using the `cget` method:

    % spot cget -color
    mottled
    % fido cget -breed
    mongrel
    %

#### How can a client set options after object creation?

Any number of options may be set at one time using the `configure` instance method. Suppose that closer inspection shows that ::fido is a rare Arctic Boar Hound of a lovely dun color:

    % fido configure -color dun -breed "Arctic Boar Hound"
    % fido cget -color
    dun
    % fido cget -breed
    Arctic Boar Hound
    %

Alternatively, the `configurelist` method takes a list of options and values; this is sometimes more convenient:

    % set features [list -color dun -breed "Arctic Boar Hound"]
    -color dun -breed {Arctic Boar Hound}
    % fido configurelist $features
    % fido cget -color
    dun
    % fido cget -breed
    Arctic Boar Hound
    %

#### How should an instance method access an option value?

There are two ways an instance method can set and retrieve an option's value. One is to use the `configure` and `cget` methods, as shown below:

    % snit::type dog {
        option -weight 10

        method gainWeight {} {
            set wt [$self cget -weight]
            incr wt
            $self configure -weight $wt
        }
    }
    ::dog
    % dog fido
    ::fido
    % fido cget -weight
    10
    % fido gainWeight
    % fido cget -weight
    11
    %

Alternatively, Snit provides a built-in array instance variable called `options`. The indices are the option names; the values are the option values. The method given above can thus be rewritten as follows:

        method gainWeight {
            incr options(-weight)
        }

As you can see, using the `options` variable involves considerably less typing. If you define `onconfigure` or `oncget` handlers, as described in the following answers, you might wish to use the `configure` and `cget` methods anyway, just so that any special processing you've implemented is sure to get done.

#### How can I catch changes to an option's value?

Use an `onconfigure` handler.

#### What is an onconfigure handler?

An `onconfigure` handler is a special kind of instance method that's called whenever the related option is given a new value via the `configure` or `configurelist` instance methods. The handler can validate the new value, pass it to some other object, and anything else you'd like it to do.

An `onconfigure` handler is defined by an `onconfigure` statement in the type definition. Here's what the default configuration behavior would look like if written as an `onconfigure` handler:

    snit::type dog {
        option -color brown

        onconfigure -color {value} {
            set options(-color) $value
        }
    }

The name of the handler is just the option name. The argument list must have exactly one argument; it can be called almost anything, but conventionally it is called "value". Within the handler, the argument is set to the new value; also, all instance variables are available, just as in an instance method.

Note that if your handler doesn't put the value in the `options` array, it doesn't get updated.

#### How can I catch accesses to an option's value?

Use an `oncget` handler.

#### What is an oncget handler?

An `oncget` handler is a special kind of instance method that's called whenever the related option's value is queried via the `cget` instance method. The handler can compute the value, retrieve it from a database, or anything else you'd like it to do.

An `oncget` handler is defined by an `oncget` statement in the type definition. Here's what the default behavior would look like if written as an `oncget` handler:

    snit::type dog {
        option -color brown

        oncget -color {
            return $options(-color)
        }
    }

The handler takes no arguments, and so has no argument list; however, all instance variables are available, just as they are in normal instance methods.

## TYPE VARIABLES

#### What is a type variable?

A type variable is a private variable associated with a Snit type rather than with a particular instance of the type. In C++ and Java, the equivalent of type variables are called static member variables. Type variables can be scalars or arrays.

#### How is a scalar type variable defined?

Scalar type variables are defined in the type definition using the `typevariable` statement. You can simply name it, or you can initialize it with a value:

    snit::type mytype {
        # Define variable "greeting" and initialize it with "Howdy!"
        typevariable greeting "Howdy!"
    }

Every object of type `mytype` now has access to a single variable called "greeting".

#### How is an array type variable defined?

Array-valued type variables are also defined using the `typevariable` command; however, you can't initialize them that way, just as you can't initialize array variables using Tcl's standard `variable` command. Type constructors are the usual way to initialize array-valued type variables.

#### Are there any limitations on type variable names?

Type variable names have the same restrictions as instance variable names.

#### Do I need to declare type variables before using them?

No. Once you've defined a type variable in the type definition, it can be used in instance methods or type methods without declaration. This differs from normal Tcl practice, in which all non-local variables in a proc need to be declared.

#### How do I pass a type variable's name to another object?

In Tk, it's common to pass a widget a variable name; for example, Tk label widgets have a `-textvariable` option which names the variable which will contain the widget's text. This allows the program to update the label's value just by assigning a new value to the variable.

If you naively pass a type variable name to the label widget, you'll be confused by the result; Tk will assume that the name names a global variable. Instead, you need to provide a fully-qualified variable name. From within an instance method or a constructor, you can fully qualify the type variable's name using the `typevarname` command:

    snit::widget mywidget {
        typevariable labeltext ""

        constructor {args} {
            # ...

            label $win.label -textvariable [typevarname labeltext]

            # ...
        }
    }

#### How do I make a type variable public?

There are two ways to do this. The preferred way is to write a pair of type methods to set and query the variable's value.

Alternatively, you can publicize the variable's name in your documentation and clients can access it directly. For example,

    snit::type mytype {
        typevariable myvariable
    }

    set ::mytype::myvariable "New Value"

As shown, type variables are stored in the type's namespace, which has the same name as the type itself.

## TYPE METHODS

#### What is a type method?

A type method is a procedure associated with the type itself rather than with any specific instance of the type.

#### How do I define a type method?

Type methods are defined in the type definition using the "typemethod" statement:

    snit::type dog {
        # List of pedigreed dogs
        typevariable pedigreed

        typemethod pedigreedDogs {} {
            return $pedigreed
        }

        # ...
    }

Suppose the `dog` type maintains a list of the names of the dogs that have pedigrees. The `pedigreedDogs` type method returns this list.

The "typemethod" statement looks just like a normal Tcl "proc", except that it appears in a `snit::type` definition. It defines the method name, the argument list, and the body of the method.

#### How does a client call a type method?

The method name becomes a subcommand of the type's command. For example,

    snit::type dog {
        option -pedigreed 0

        # List of pedigreed dogs
        typevariable pedigreed

        typemethod pedigreedDogs {} {
            return $pedigreed
        }

        # ...
    }

    dog spot -pedigreed 1
    dog fido

    foreach dog [dog pedigreedDogs] { ... }

#### Are there any limitations on type method names?

Not really, so long as you avoid the standard type method names:

`create` and `info`.

#### How do I make a type method private?

It's sometimes useful to define private type methods, that is, type methods intended to be called only by other type or instance methods of the same object.

Snit doesn't implement any access control on type methods; by convention, the names of public methods begin with a lower-case letter, and the names of private methods begin with an upper-case letter.

Alternatively, a Snit "proc" can be used as a private type method; see PROCS.

#### Are there any limitations on type method arguments?

Method argument lists are defined just like normal Tcl proc argument lists; they can include default values, and the "args" argument. However, every type method is called with an implicit argument called "type" that contains the name of the type command. In addition, type methods should by convention avoid using the names of the arguments implicitly defined for instance methods.

#### How does an instance or type method call a type method?

If an instance or type method needs to call a type method, it should use "$type" to do so:

    snit::type dog {

        typemethod pedigreedDogs {} { ... }

        typemethod printPedigrees {} {
            foreach obj [$type pedigreedDogs] { ... }
        }
    }

#### How do I pass a type method as a callback?

It's common in Tcl to pass a snippet of code to another object, for it to call later. Because types cannot be renamed, the thing to do is just use the type name, or, if the callback is registered from within a type method, "`$type`". For example, suppose we want to print a list of pedigreed dogs when a Tk button is pushed:

    button .btn -text "Pedigrees" -command [list dog printPedigrees]
    pack .btn

## PROCS

#### What is a proc?

A Snit "proc" is really just a Tcl proc defined within the type's namespace. You can use procs for private code that isn't related to any particular instance. For example, I often find myself writing a proc to pop the first item off of a list stored in a variable.

#### How do I define a proc?

Procs are defined by including a "proc" statement in the type definition:

    snit::type mytype {
        # Pops and returns the first item from the list stored in the
        # listvar, updating the listvar
       proc pop {listvar} { ... }

       # ...
    }

#### Are there any limitations on proc names?

Any name can be used, so long as it does not begin with "Snit_"; names beginning with "Snit_" are reserved for Snit's own use. However, the wise programmer will avoid proc names like "set", "list", "if", and so forth that would shadow standard Tcl command names.

By convention, proc names, being private, begin with a capital letter.

#### How does a method call a proc?

Just like it calls any Tcl command. For example,

    snit::type mytype {
        # Pops and returns the first item from the list stored in the
        # listvar, updating the listvar
        proc Pop {listvar} { ... }

        variable requestQueue {}

        # Get one request from the queue and process it.
        method processRequest {} {
            set req [Pop requestQueue]
        }
    }

#### How can I pass a proc to another object as a callback?

I tend to use type or instance methods for this purpose and ignore procs altogether. But if you really need to, the `codename` command returns the proc's fully qualified name.

## TYPE CONSTRUCTORS

#### What is a type constructor?

A type constructor is a body of code that initializes the type as a whole, rather like a C++ static initializer. The body of a type constructor is executed once when the type is defined, and never again.

A type can have at most one type constructor.

#### How do I define a type constructor?

A type constructor is defined by using the `typeconstructor` statement in the type definition. For example, suppose the type uses an array-valued type variable as a look up table:

    % snit::type mytype {
        typevariable lookupTable

        typeconstructor {
            array set lookupTable {key value...}
        }
    }
    ::mytype
    %

## CONSTRUCTORS

#### What is a constructor?

In object-oriented programming, an object's constructor is responsible for initializing the object completely at creation time. The constructor receives the list of options passed to the `snit::type` command's create method and can then do whatever it likes. That might include computing instance variable values, reading data from files, creating other objects, updating type variables, and so forth.

The constructor doesn't return anything.

#### How do I define a constructor?

A constructor is defined by using the `constructor` statement in the type definition. Suppose that it's desired to keep a list of all pedigreed dogs. The list can be maintained in a type variable and retrieved by a type method. Whenever a dog is created, it can add itself to the list--provided that it's registered with the American Kennel Club.

    % snit::type dog {
        option -akc 0

        typevariable akcList {}

        constructor {args} {
            $self configurelist $args

            if {$options(-akc)} {
                lappend akcList $self
            }
        }

        typemethod akclist {} {
            return $akcList
        }
    }
    ::dog
    % dog spot -akc 1
    ::spot
    % dog fido
    ::fido
    % dog akclist
    ::spot
    %

#### What does the default constructor do?

If you don't provide a constructor explicitly, you get the default constructor, which looks like this:

    % snit::type dog {
        option -breed mongrel
        option -color brown
        option -akc 0

        constructor {args} {
            $self configurelist $args
        }
    }
    ::dog
    % dog spot -breed dalmatian -color spotted -akc 1
    ::spot
    %

When the constructor is called, "args" will be set to the list of arguments that follow the object's name. The constructor is allowed to interprete this list any way it chooses; the normal convention is to assume that it's a list of option names and values, as shown in the example above. If you simply want to save the option values, you should use the `configurelist` method, as shown.

#### Can I choose a different command line syntax for the constructor?

Yes, you can. For example, suppose we wanted to be sure that the breed was explicitly stated for every dog at creation time, and couldn't be changed thereafter. One way to do that is as follows:

    % snit::type dog {
        variable breed

        option -color brown
        option -akc 0

        constructor {theBreed args} {
            set breed $theBreed
            $self configurelist $args
        }

        method breed {} {
            return $breed
        }
    }
    ::dog
    % dog spot dalmatian -color spotted -akc 1
    ::spot
    % spot breed
    dalmatian
    %

The drawback is that this creation syntax is non-standard, and may limit the compatibility of your new type with other people's code. For example, Snit generally assumes that components use the standard creation syntax.

#### Are there any limitations on constructor arguments?

Constructor argument lists are defined just like normal Tcl proc argument list; they can include default values, and the "args" argument. However, the constructor is called with a number of implicit arguments provided by Snit in addition to those explicitly defined. The names of these implicit arguments may not used to name explicit arguments.

#### What implicit arguments are passed to the constructor?

The constructor gets the same implicit arguments that are passed to instance methods: `type`, `selfns`, `win`, and `self`.

## DESTRUCTORS

#### What is a destructor?

A destructor is a special kind of method that's called when an object is destroyed. It's responsible for doing any necessary clean-up when the object goes away: destroying components, closing files, and so forth.

#### How do I define a destructor?

Destructors are defined by using the `destructor` statement in the type definition. Suppose we're maintaining a list of pedigreed dogs; then we'll want to remove dogs from it when they are destroyed.

    % snit::type dog {
        option -akc 0

        typevariable akcList {}

        constructor {args} {
            $self configurelist $args

            if {$options(-akc)} {
                lappend akcList $self
            }
        }

        destructor {
            set ndx [lsearch $akcList $self]

            if {$ndx != -1} {
                set akcList [lreplace $akcList $ndx $ndx]
            }
        }

        typemethod akclist {} {
            return $akcList
        }
    }
    ::dog
    % dog spot -akc 1
    ::spot
    % dog fido -akc 1
    ::fido
    % dog akclist
    ::spot ::fido
    % fido destroy
    % dog akclist
    ::spot
    %

#### Are there any limitations on destructor arguments?

Yes; a destructor has no explicit arguments.

#### What implicit arguments are passed to the destructor?

The destructor gets the same implicit arguments that are passed to instance methods: `type`, `selfns`, `win`, and `self`.

#### Must components be destroyed explicitly?

Yes and no.

For a Snit megawidget (`snit::widgets` and `snit::widgetadaptors`), any widget components created by it will be destroyed automatically when the megawidget is destroyed, in keeping with normal Tk behavior (destroying a parent widget destroys the whole tree). On the other hand, all non-widget components of a Snit megawidget, and all components of a normal `snit::type` object, must be destroyed explicitly in a destructor.

## COMPONENTS

#### What is a component?

Often an object will create and manage a number of other objects. One example is a Snit megawidget that composes a number of Tk widgets. These objects are part of the main object and are thus are called components of it.

But Snit also has a more precise meaning for "component". The components of a Snit object are those objects created by it to which methods and options can be delegated. See DELEGATION for more information about delegation.

#### How do I create a component?

First, you must decide what role a component plays within your object, and give the role a name. For example, suppose your `dog` object creates a `tail` object (the better to wag with, no doubt). The `tail` object will have some command name, but you tell Snit about it using its role name, as follows:

    % snit::type dog {
        # Define component name as an instance variable
        variable mytail

        constructor {args} {
            # Create and save the component's command
            install mytail using tail %AUTO% -partof $self
            $self configurelist $args
        }

        method wag {} {
            $mytail wag
        }
    }
    ::dog

As shown here, it doesn't matter what the `tail` object's real name is; the `dog` object refers to it by its component name.

The above example shows one way to delegate the "wag" method to the "mytail" component; see DELEGATION for an easier way.

#### How is a component named?

A component has two names. The first name represents the role the component object plays within the Snit object. This is the component name proper, and is the name used to refer to the component within Snit code. The second name is the name of the actual component object created by the Snit object's constructor. This second name is always a Tcl command name, and is referred to as the component's object name.

In the example in the previous FAQ, the component name is "mytail"; the "mytail" component's object name is chosen automatically by Snit since %AUTO% was used when the component object was created.

#### What does the install command do?

The `install` command creates the component using the specified command (`tail %AUTO% -partof $self`), and assigns the result to the `mytail` variable. For `snit::types`, the `install` command shown above is equivalent to the following command:

            set mytail [tail %AUTO% -partof $self]

For `snit::widgets` and `snit::widgetadaptors`, however, the `install` command also queries the Tk option database and initializes the component's options accordingly. For consistency, it's a good idea to get in the habit of using `install` for all components.

#### Are there any limitations on component names?

Yes. `snit::widget` and `snit::widgetadaptor` have a special component called the `hull` component; thus, the name `hull` should be used for no other purpose.

Component names are in fact instance variable names, and so follow the rules for instance variables.

#### Are there any limitations on component object names?

Yes. Component objects which are Tk widgets or megawidgets must have valid Tk window names. Component objects which are not widgets or megawidgets must have fully-qualified command names, i.e., names which include the full namespace of the command. Note that Snit always creates objects with fully qualified names. Second, component object names must be unique. This is no problem for widget components, since widget names are always unique; but consider the following code:

        snit::type tail { ... }

        snit::type dog {
            delegate method wag to mytail

            constructor {} {
                install mytail using tail mytail
            }
        }

This code uses the component name, "mytail", as the component object name. This is not good, and here's why: Snit instance code executes in the Snit type's namespace. In this case, the mytail component is created in the ::dog:: namespace, and will thus have the name ::dog::mytail.

Now, suppose you create two dogs. Both will have a mytail component called ::dog::mytail. In other words, you've got two dogs with one tail between them. This is very bad. Here are a couple of ways to avoid it:

First, if the component type is a `snit::type` you can specify %AUTO% as its name, and be guaranteed to get a unique name. This is the safest thing to do:

        install mytail using tail %AUTO%

If the component type isn't a `snit::type` you can base the component's object name on the type's name in some way:

         install mytail using tail $self.mytail

This isn't as safe, but should usually work out okay.

#### Must I destroy the components I create?

That depends. When a parent widget is destroyed, all child widgets are destroyed automatically. Thus, if your object is a `snit::widget` or `snit::widgetadaptor` you don't need to destroy any components that are widgets.

Any non-widget components, however, and all components of a `snit::type` object, must be destroyed explicitly. This is true whether you assign them a component name or not.

    % snit::type dog {
        variable mytail

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

        destructor {
            $mytail destroy
        }
    }
    ::dog
    %

Note that this code assumes that `tail` is also a `snit::type`; if not, it might need to be destroyed in some other way.

#### Can I expose a component's object command as part of my interface?

Yes, and there are two ways to do it. The most appropriate way is usually to use delegation. Delegation allows you to pass the options and methods you specify along to particular components. This effectively hides the components from the users of your type, and ensures good encapsulation.

However, there are times when it's appropriate, not to mention simpler, just to make the entire component part of your type's public interface.

#### How do I expose a component's object command?

Use the `expose` statement. For example, suppose you're creating a combobox megawidget which owns a listbox widget, and you want to make the listbox's entire interface public. You can do this:

    snit::widget combobox {
         expose listbox

         constructor {args} {
             install listbox using listbox $win.listbox ....

             #...
         }

         #...
    }

    combobox .mycombo
    .mycombo listbox configure -width 30

The `expose` statement exposes the named component by defining a method of the same name. The method's arguments are passed along to the component. Thus, the above code sets the listbox component's "-width" to 30.

If called with no arguments, the method returns the component's object name:

    % .mycombo listbox
    .mycombo.listbox

Usually you'll let the method name be the same as the component name; however, you can rename it if necessary. The code in the following listing exposes the same interface as the previous example:

    snit::widget combobox {
         expose mylistbox as listbox

         constructor {args} {
             install mylistbox using listbox $win.mylistbox ....

             #...
         }

         #...
    }
    combobox .mycombo
    .mycombo listbox configure -width 30

## DELEGATION

#### What is delegation?

Delegation, simply put, is when you pass a task you've been given to one of your assistants. (You do have assistants, don't you?) Snit objects can do the same thing. The following example shows one way in which the `dog` object can delegate its `wag` method and its `-taillength` option to its `tail` component.

    % snit::type dog {
        variable mytail

        option -taillength

        onconfigure -taillength {value} {
             $mytail configure -length $value
        }

        oncget -taillength {
             $mytail cget -length
        }

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

        method wag {} {
            $mytail wag
        }
    }
    ::dog
    % snit::type tail {
        option -length 5
        option -partof
        method wag {} { return "Wag, wag, wag."}
    }
    ::tail
    % dog spot -taillength 7
    ::spot
    % spot cget -taillength
    7
    % spot wag
    Wag, wag, wag.
    %

This is the hard way to do it, by it demonstrates what delegation is all about. See the following answers for the easy way to do it.

Note that the constructor calls the `configurelist` method after it creates its `tail`; otherwise, if `-taillength` appeared in the list of `args` we'd get an error.

#### How can I delegate a method to a component object?

Delegation occurs frequently enough that Snit makes it easy. Any method can be delegated to any component by placing a single `delegate` statement in the type definition. (See COMPONENTS for more information about component names.)

For example, here's a much better way to delegate the `dog` object's `wag` method:

    % snit::type dog {
        delegate method wag to mytail

        constructor {args} {
            install mytail using tail %AUTO% -partof $self
            $self configurelist $args
        }
    }
    ::dog
    % snit::type tail {
        option -length 5
        option -partof
        method wag {} { return "Wag, wag, wag."}
    }
    ::tail
    % dog spot
    ::spot
    % spot wag
    Wag, wag, wag.
    %

This code has the same affect as the code shown under the previous question: when a `dog`'s `wag` method is called, the call and its arguments are passed along automatically to the `tail` object.

Note that when a component is mentioned in a `delegate` statement, the component's instance variable is defined implicitly.

Note also that you can define a method name using the `method` statement, or you can define it using `delegate`; you can't do both.

#### Can I delegate to a method with a different name?

Suppose the `tail` object has a `wiggle` method instead of a `wag` method, and you want to delegate the `dog`'s `wag` method to the `tail`'s `wiggle` method. It's easily done:

    % snit::type dog {
        delegate method wag to mytail as wiggle

        constructor {args} {
            install mytail using tail %AUTO% -partof $self
            $self configurelist $args
        }
    }
    ::dog
    % snit::type tail {
        option -length 5
        option -partof
        method wiggle {} { return "Wag, wag, wag."}
    }
    ::tail
    % dog spot
    ::spot
    % spot wag
    Wag, wag, wag.
    %

#### Can I delegate to a method with additional arguments?

Suppose the `tail` object has a `wag` method that takes as an argument the number of times the tail should be wagged. You want to delegate the `dog`'s `wag` method to the `tail`'s `wag` method, specifying that the tail should be wagged three times. It's easily done:

    % snit::type dog {
        delegate method wag to mytail as {wag 3}

        constructor {args} {
            install mytail using tail %AUTO% -partof $self
            $self configurelist $args
        }
    }
    ::dog
    % snit::type tail {
        option -length 5
        option -partof
        method wag {count} {
            return [string repeat "Wag " $count]
        }
    }
    ::tail
    % dog spot
    ::spot
    % spot wag
    Wag Wag Wag
    %

#### How can I delegate an option to a component object?

The first question in this section (see DELEGATION) shows one way to delegate an option to a component; but this pattern occurs often enough that Snit makes it easy. For example, every `tail` object has a `-length` option; we want to allow the creator of a `dog` object to set the tail's length. We can do this:

    % snit::type dog {
        delegate option -length to mytail

        constructor {args} {
            install mytail using tail %AUTO% -partof $self
            $self configurelist $args
        }
    }
    ::dog
    % snit::type tail {
        option -partof
        option -length 5
    }
    ::tail
    % dog spot -length 7
    ::spot
    % spot cget -length
    7
    %

This produces nearly the same result as the `oncget` and `onconfigure` handlers shown under the first question in this section: whenever a `dog` object's `-length` option is set or retrieved, the underlying `tail` object's option is set or retrieved in turn.

Note that you can define an option name using the `option` statement, or you can define it using `delegate`; you can't do both.

#### Can I delegate to an option with a different name?

In the previous answer we delegated the `dog`'s `-length` option down to its `tail`. This is, of course, wrong. The dog has a length, and the tail has a length, and they are different. What we'd really like to do is give the `dog` a `-taillength` option, but delegate it to the `tail`'s `-length` option:

    % snit::type dog {
        delegate option -taillength to mytail as -length

        constructor {args} {
            set mytail [tail %AUTO% -partof $self]
            $self configurelist $args
        }
    }
    ::dog
    % snit::type tail {
        option -partof
        option -length 5
    }
    ::tail
    % dog spot -taillength 7
    ::spot
    % spot cget -taillength
    7
    %

#### How can I delegate any unrecognized method or option to a component object?

It may happen that a Snit object gets most of its behavior from one of its components. This often happens with `snit::widgetadaptors`, for example, where we wish to slightly the modify the behavior of an existing widget. To carry on with our `dog` example, however, suppose that we have a `snit::type` called `animal` that implements a variety of animal behaviors--moving, eating, sleeping, and so forth. We want our `dog` objects to inherit these same behaviors, while adding dog-like behaviors of its own. Here's how we can give a `dog` methods and options of its own while delegating all other methods and options to its `animal` component:

    % snit::type dog {
        delegate option * to animal
        delegate method * to animal

        option -akc 0

        constructor {args} {
            install animal using animal %AUTO% -name $self
            $self configurelist $args
        }

        method wag {} {
            return "$self wags its tail"
        }
    }
    ::dog
    %

That's it. A `dog` is now an `animal` which has a `-akc` option and can `wag` its tail.

Note that we don't need to specify the full list of method names or option names which `animal` will receive. It gets anything `dog` doesn't recognize--and if it doesn't recognize it either, it will simply throw an error, just as it should.

#### How can I delegate all but certain methods or options to a component?

In the previous answer, we said that every `dog` is an `animal` by delegating all unknown methods and options to the `animal` component. But what if the `animal` type has some methods or options that we'd like to suppress?

One solution is to explicitly delegate all the options and methods, and forgo the convenience of `delegate method *` and `delegate option *`. But if we wish to suppress only a few options or methods, there's an easier way:

    % snit::type dog {
        delegate option * to animal except -legs
        delegate method * to animal except {fly climb}

        # ...

        constructor {args} {
            install animal using animal %AUTO% -name $self -legs 4
            $self configurelist $args
        }

        # ...
    }
    ::dog
    %

Dogs have four legs, so we specify that explicitly when we create the `animal` component, and explicitly exclude `-legs` from the set of delegated options. Similarly, dogs can neither fly nor climb, so we exclude those `animal` methods as shown.

## WIDGETS

#### What is a snit::widget?

A `snit::widget` is the Snit version of what Tcl programmers usually call a "megawidget": a widget-like object usually consisting of one or more Tk widgets all contained within a Tk frame.

A `snit::widget` is also a special kind of `snit::type`. Just about everything in this FAQ list that relates to `snit::types` also applies to `snit::widgets`.

#### How do I define a snit::widget?

`snit::widgets` are defined using the `snit::widget` command, just as `snit::types` are defined by the `snit::type` command.

The body of the definition can contain all of the same kinds of statements, plus a couple of others which will be mentioned below.

#### How do snit::widgets differ from snit::types?

- The name of an instance of a `snit::type` can be any valid Tcl command name, in any namespace. The name of an instance of a `snit::widget` must be a valid Tk widget name, and its parent widget must already exist.

- An instance of a `snit::type` can be destroyed by calling its `destroy` method. Instances of a `snit::widget` have no destroy method; use the Tk `destroy` command instead.

- Every instance of a `snit::widget` has one predefined component called its `hull` component. The hull is a Tk `frame` or `toplevel` widget; any other widgets created as part of the `snit::widget` will usually be contained within this frame or toplevel.

- `snit::widgets` can have their options receive default values from the Tk option database.

#### What is a hull component?

Snit can't create a Tk widget object; only Tk can do that. Thus, every instance of a `snit::widget` must be wrapped around a genuine Tk widget; this Tk widget is called the hull component. Snit effectively piggybacks the behavior you define (methods, options, and so forth) on top of the hull component so that the whole thing behaves like a standard Tk widget.

For `snit::widgets` the hull component must be a Tk `frame` or `toplevel` widget; any other widgets created as part of the `snit::widget` will be contained within this frame or toplevel.

`snit::widgetadaptors` differ from `snit::widgets` chiefly in that any kind of widget can be used as the hull component; see WIDGETADAPTORS.

#### How can I set the hull type for a snit::widget?

A `snit::widget`'s hull component will usually be a Tk `frame` widget; however, it may also be a `toplevel` widget. You can explicitly choose one or the other by including the `hulltype` command in the widget definition:

    snit::widget mytoplevel {
        hulltype toplevel

        # ...
    }

If no `hulltype` command appears, the hull will be a `frame`.

#### How should I name widgets which are components of a snit::widget?

Every widget, whether a genuine Tk widget or a Snit megawidget, has to have a valid Tk window name. When a `snit::widget` is first created, its instance name, `$self`, is a Tk window name; however, if the `snit::widget` is used as the hull component by a `snit::widgetadaptor` its instance name will be changed to something else. For this reason, every `snit::widget` method, constructor, destructor, and so forth is passed another implicit argument, `$win`, which is the window name of the megawidget. Any children must be named using `$win` as the root.

Thus, suppose you're writing a toolbar widget, a frame consisting of a number of buttons placed side-by-side. It might look something like this:

    snit::widget toolbar {
        delegate option * to hull

        constructor {args} {
            button $win.open -text Open -command [mymethod open]
            button $win.save -text Save -command [mymethod save]

            # ....

            $self configurelist $args

        }
    }

See also the question on renaming objects, toward the top of this file.

## WIDGETADAPTORS

#### What is a snit::widgetadaptor?

A `snit::widgetadaptor` is a kind of `snit::widget`. Whereas a `snit::widget`'s hull is automatically created and is always a Tk frame, a `snit::widgetadaptor` can be based on any Tk widget--or on any Snit megawidget, or even (with luck) on megawidgets defined using some other package.

It's called a "widget adaptor" because it allows you to take an existing widget and customize its behavior.

#### How do I define a snit::widgetadaptor?

Using the `snit::widgetadaptor` command. The definition for a `snit::widgetadaptor` looks just like that for a `snit::type` or `snit::widget`, except that the constructor must create and install the hull component.

For example, the following code creates a read-only text widget by the simple device of turning its "insert" and "delete" methods into no-ops. Then, we define new methods, "ins" and "del", which get delegated to the hull component as "insert" and "delete". Thus, we've adapted the text widget and given it new behavior while still leaving it fundamentally a text widget.

    % ::snit::widgetadaptor rotext {

        constructor {args} {
            # Create the text widget; turn off its insert cursor
            installhull using text -insertwidth 0

            # Apply any options passed at creation time.
            $self configurelist $args
        }

        # Disable the text widget's insert and delete methods, to
        # make this readonly.
        method insert {args} {}
        method delete {args} {}

        # Enable ins and del as synonyms, so the program can insert and
        # delete.
        delegate method ins to hull as insert
        delegate method del to hull as delete

        # Pass all other methods and options to the real text widget, so
        # that the remaining behavior is as expected.
        delegate method * to hull
        delegate option * to hull
    }
    ::rotext
    %

The most important part is in the constructor. Whereas `snit::widget` creates the hull for you, `snit::widgetadaptor` cannot--it doesn't know what kind of widget you want. So the first thing the constructor does is create the hull component (a Tk text widget in this case), and then installs it using the `installhull` command.

Note: There is no instance command until you create one by installing a hull component. Any attempt to pass methods to $self prior to calling `installhull` will fail.

#### Can I adapt a widget created by someone else?

Yes.

At times, it can be convenient to adapt a widget created by another party. For example, the Bwidget `PagesManager` widget manages a set of `frame` widgets, only one of which is visible at a time. The application chooses which `frame` is visible. These `frames` are created by the `PagesManager` itself, using its `add` method.

In a case like this, the Tk widget will already exist when the `snit::widgetadaptor` is created. Snit provides an alternate form of the `installhull` command for this purpose:

    snit::widgetadaptor pageadaptor {
        constructor {args} {
            # The widget already exists; just install it.
            installhull $win

            # ...
        }
    }

## THE TK OPTION DATABASE

#### What is the Tk option database?

The Tk option database is a database of default option values maintained by Tk itself; every Tk application has one. The concept of the option database derives from something called the X Windows resource database; however, the option database is available in every Tk implementation, including those which do not use the X Windows system (e.g., Microsoft Windows).

Full details about the Tk option database are beyond the scope of this document; both Practical Programming in Tcl and Tk by Welch, Jones, and Hobbs, and Effective Tcl/Tk Programming by Harrison and McClennan., have good introductions to it.

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.

- If the widget's default widget class is not what is desired, set it explicitly using the `widgetclass` statement in the widget definition.

- When defining or delegating options, specify the resource and class names explicitly when necessary.

- Use the `installhull using` command to create and install the hull for `snit::widgetadaptors`.

- Use the `install` command to create and install all other components.

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.

#### Do snit::types use the Tk option database?

No, they don't; querying the option database requires a Tk window name, and snit::types don't have one.

Only `snit::widgets` and `snit::widgetadaptors` query the option database.

#### What is my snit::widget's widget class?

Every Tk widget has a "widget class": a name that is used when adding option settings to the database. For Tk widgets, the widget class is the same as the widget command name with an initial capital. For example, the widget class of the Tk `button` widget is "Button".

Similarly, the widget class of a `snit::widget` defaults to the unqualified type name with the first letter capitalized. For example, the widget class of

    snit::widget ::mylibrary::scrolledText { ... }

is "ScrolledText".

The widget class can also be set explicitly using the `widgetclass` statement within the `snit::widget` definition:

    snit::widget ::mylibrary::scrolledText {
        widgetclass Text

        # ...
    }

The above definition says that a `scrolledText` megawidget has the same widget class as an ordinary `text` widget. This might or might not be a good idea, depending on how the rest of the megawidget is defined, and how its options are delegated.

#### What is my snit::widgetadaptor's widget class?

The widget class of a `snit::widgetadaptor` is just the widget class of its hull widget; Snit has no control over this.

Note that the widget class can be changed only for `frame` and `toplevel` widgets, which is why these are the valid hull types for `snit::widgets`.

Try to use `snit::widgetadaptors` only to make small modifications to another widget's behavior. Then, it will usually not make sense to change the widget's widget class anyway.

#### What are option resource and class names?

Every Tk widget 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 `configure` and `cget` commands.

The resource and class names are used to initialize option default values by querying the 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 Tk `text` widget options:

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

As is easily seen, sometimes the resource and class names can be inferred from the option name, but not always.

#### What are the resource and class names for my megawidget's options?

For options implicitly delegated to a component using `delegate option *`, the resource and class names will be exactly those defined by the component. The `configure` method returns these names, along with the option's default and current values:

    % snit::widget mytext {
        delegate option * to text

        constructor {args} {
            install text using text .text
            # ...
        }

        # ...
    }
    ::mytext
    % mytext .text
    .text
    % .text configure -padx
    -padx padX Pad 1 1
    %

For all other options (whether locally defined or explicitly delegated), the resource and class names can be defined explicitly, or they can be allowed to have default values.

By default, the resource name is just the option name minus the hyphen; the the class name is just the option name with an initial capital letter. For example, suppose we explicitly delegate "-padx":

    % snit::widget mytext {
        option -myvalue 5

        delegate option -padx to text
        delegate option * to text

        constructor {args} {
            install text using text .text
            # ...
        }

        # ...
    }
    ::mytext
    % mytext .text
    .text
    % .text configure -mytext
    -mytext mytext Mytext 5 5
    % .text configure -padx
    -padx padx Padx 1 1
    %

Here the resource and class names are chosen using the default rules. Often these rules are sufficient, but in the case of "-padx" we'd most likely prefer that the option's resource and class names are the same as for the built-in Tk widgets. This is easily done:

    % snit::widget mytext {
        delegate option {-padx padX Pad} to text

        # ...
    }
    ::mytext
    % mytext .text
    .text
    % .text configure -padx
    -padx padX Pad 1 1
    %

#### How does Snit initialize my megawidget's locally-defined options?

The option database is queried for each of the megawidget's locally-defined options, using the option's resource and class name. If the result isn't "", then it replaces the default value given in widget definition. In either case, the default can be overriden by the caller. For example,

    option add *Mywidget.texture pebbled

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

    mywidget .mywidget -texture greasy

Here, "-texture" 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".

#### How does Snit initialize delegated options?

That depends on whether the options are delegated to the hull, or to some other component.

#### How does Snit initialize options delegated to the hull?

A `snit::widget`'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:

    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]

The question is, what are the values of variables A, B, C and D?

The value of A is "sunken". The hull is a Tk frame which has been given the widget class "Mywidget"; it will automatically query the option database and pick up this value. Since the -relief option is implicitly delegated to the hull, Snit takes no action.

The value of B is "red". The hull will automatically pick up the value "green" for its -background option, just as it picked up the -relief value. However, Snit knows that -hullbackground is mapped to the hull's -background option; hence, it queries the option database for -hullbackground and gets "red" and updates the hull accordingly.

The value of C is also "red", because -background is implicitly delegated to the hull; thus, retrieving it is the same as retrieving -hullbackground. Note that this case is unusual; the -background option should probably have been excluded using the delegate statement's "except" clause, or (more likely) delegated to some other component.

The value of D is "5", but not for the reason you think. Note that as it is defined above, the resource name for -borderwidth defaults to "borderwidth", whereas the option database entry is "borderWidth", in accordance with the standard Tk naming for this option. As with -relief, the hull picks up its own "-borderwidth" 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. To avoid confusion, the -borderwidth option should have been delegated like this:

        delegate option {-borderwidth borderWidth BorderWidth} to hull

For `snit::widgetadaptors`, 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 `snit::widgetadaptor` must call `installhull` in its constructor. The normal way to do this is as follows:

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

In this case, the `installhull` command will create the hull using a command like this:

        set hull [text $win -foreground white]

The hull is a `text` widget, so its widget class is "Text". Just as with `snit::widget` hulls, Snit assumes that it will pick up all of its normal option values automatically, without help from Snit. Options delegated from a different name are initialized from the option database in the same way as described above.

In earlier versions of Snit, `snit::widgetadaptors` were expected to call `installhull` like this:

        installhull [text $win -foreground white]

This form still works--but Snit will not query the option database as described above.

#### How does Snit initialize options delegated to other components?

For hull components, Snit assumes that Tk will do most of the work automatically. Hull components are somewhat more complicated, because they are matched against the option database twice.

A component widget remains a widget still, and is therefore initialized from the option database in the usual way. A `text` widget remains a `text` widget whether it is a component of a megawidget or not, and will be created as such.

But then, the option database is queried for all options delegated to the component, and the component is initialized accordingly--provided that the `install` command is used to create it.

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:

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

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

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

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

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

The `install` command does the following:

- Builds a list of the options explicitly included in the `install` command--in this case, -foreground.

- Queries the option database for all options delegated explicitly to the named component.

- 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 include options (-foreground) will override anything read from the option database.

- If the widget definition implicitly delegated options to the component using "delegate option *", then Snit calls the newly created component's `configure` 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 which were not explicitly included in the `install` command. For all such options, Snit queries the option database and configures the component accordingly.

You don't really need to know all of this; just use `install` to install your components, and Snit will try to do the right thing.

#### What happens if I install a non-widget as a component of widget?

A `snit::type` never queries the option database. However, a `snit::widget` can have non-widget components. And if options are delegated to those components, and if the `install` command is used to install those components, then they will be initialized from the option database just as widget components are.

However, when used within a megawidget, `install` assumes that the created component uses a reasonably standard widget-like creation syntax. If it doesn't, don't use `install`.

Copyright © 2003, by William H. Duquette. All rights reserved.