This package defines the "feather::command" interface, creates some commands
which use that interface and provides the infrastructure to support objects
which support the "feather::command" interface.
It took a long time to get command objects to work properly; by properly I mean that you can do this:
set square [feather::lambda {x} {expr {$x * $x}}]
$square 12
set square [feather::lambda {x} {expr {$x * $x}}]
invoke $square 12
Originally I thought that it was not possible to do it properly without a patch to the core. However after a lot of investigation and experimenting I found that it was actually possible after all.
Resolving an object to a particular command is done by converting the object to the "cmdName" type. This conversion process looks up the string representation of the object according to Tcl's command resolution rules (possibly augmented by resolvers) and caches the resulting command in the internal representation of the object.
Feather intercepts all calls through the tclCmdNameType which defines the
"cmdName" structure to add its command object support. Basically it piggybacks
the command object on top of the resolved commands internal representation and
when the resolved command is invoked it invokes the invoke method
of the command object's "feather::command" interface.
Command objects have to be opaque and support the "feather::opaque" interface, otherwise they will not work. If you need to create a non-opaque command object, such as for a widget then you should use a normal command, or take a look at Feather::Override.
Because Feather command objects are not proper commands you cannot treat them as commands. e.g. you cannot rename them.
One thing to note is that the string representation of command objects must not clash with procedures, otherwise you will have strange behaviour.
The interface contains the following members.
int (*invoke) (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []);
objv[0] is a pointer to the Tcl command
object.
If clientData is set to NULL then the objv[0] is
of the correct type and the internal representation can be extracted directly
from it. Otherwise clientData points to a
Feather_OpaqueObject which should be converted to the internal
representation.
You should not convert objv[0] to the correct command object type
because that could reduce the performance as next time you use it as a command
it will be converted back to the "cmdName" type.