[comment {-*- mode: tcl ; fill-column: 90 -*-}] When the set of predefined argument types is not enough the oldest way of handling the situation is falling back to the structures used by Tcl to manage values, i.e. [type Tcl_Obj*]. [list_begin enumerated] [enum][vset base][example { critcl::cproc hello {object x} void { /* Tcl_Obj* x */ int len; char* str = Tcl_GetStringFromObj (x, &len); printf("hello world, from %s (%d bytes)\n", str, len); } }][vset rebuild] [enum] Having direct access to the raw [type Tcl_Obj*] value all functions of the public Tcl API for working with Tcl values become usable. The downside of that is that all the considerations for handling them apply as well. [para] In other words, the C code becomes responsible for handling the reference counts correctly, for duplicating shared [type Tcl_Obj*] structures before modifying them, etc. [para] One thing the C code is allowed to do without restriction is to [term shimmer] the internal representation of the value as needed, through the associated Tcl API functions. For example [fun Tcl_GetWideIntFromObj] and the like. It actually has to be allowed to do so, as the type checking done as part of such conversions is now the responsibility of the C code as well. [para] For the predefined types this is all hidden in the translation layer generated by [vset critcl]. [para] If more than one command has to perform the same kind of checking and/or conversion it is recommended to move the core of the code into proper C functions for proper sharing among the commands. [enum] This is best done by defining a custom argument type using [vset critcl] commands. This extends the translation layer [vset critcl] is able to generate. The necessary conversions, type checks, etc. are then again hidden from the bulk of the application C code. [para] We will come back to this. [list_end]