Version 12 of command

Updated 2005-06-30 11:49:53 by schlenk

Richard Suchenwirth - Tcl is the Tool Command Language. Execution is done by splitting scripts into commands (by newline or semicolon). A command is a sequence of words, the first being the command name, the rest its arguments. (So far from Tcl syntax). A specialized mantra would say "everything is a command", even what other languages call "control structures" (if, while, for...) or "declarations" (global, proc, variable...).

All available command names at a given time (and namespace) are returned by

 info commands

They may have come from several sources:

  • C-implemented commands
  • Tcl-implemented procs, listed in info procs
  • Aliases for other commands, listed in interp aliases {}
  • Tk widgets use their pathname as command; you can test whether a string is a widget command with winfo exists $name
  • images also use their name as command name, listed in image names
  • OO systems like incr Tcl also use object names in the command position

The following proc returns the type of a command, or an empty string if the name is not a command:

 proc command'type2 name {
    foreach {result    condition} {
             unsourced {[info command $name]=="" 
                        && [info ex ::auto_index($name)]}
             {}        {[info command $name]==""}
             proc      {[info proc $name]==$name}
             alias     {[lsearch [interp aliases {}] $name]>=0}
             image     {[lsearch [image names] $name]>=0}
             widget    {[winfo exists $name]}
             command   1
    } {if $condition {return $result}}
 } ;# RS

To introspect commands in other than the current namespace, walk the tree with namespace children.


Cameron Laird pointed out: "The succinct command'type2 definition is slightly non-robust in the face of, for example,

  proc tcl* args {}

It's far from alone in that minor weakness, of course."

And there is a way to fix this: while [info proc] gets disturbed by the asterisk (and returns a number of proc names that start with tcl), other subcommands like [info args] don't do glob matching, so replacing the "proc" case above with

             proc      {![catch {info args $name}]}

fixes the problem. Thank you! (RS)

CL responds with a couple of observations: 1. This is minor stuff. There are applications in production that have far bigger robustness problems, yet have been satisfying end-users for years. I can't even bring myself to call this a problem--it's more of a footnote. 2. On the other hand, it interests and entertains me how often programs admit minor transformations that are strictly superior in the sense that they're as readable and succinct, while being "more correct" (satisfying over a wider input space, for example). I salute Richard for so quickly finding such a transformation in this case.


SS 30 Jun 2005:

schlenk just produced this procedure to check if a given command exists, it is in theory trivial but in pratice to get it right is not too simple, so maybe it's a good idea to put the proc here:

 proc cmd_exists {cmd} {
     string equal "" [namespace eval :: namespace which [list $cmd]]
 }

Can't you just use info command?

$ tclsh

  % info command info
  info
  % info command nonsense
  %

schlenk Not if you have funny command names that are glob patterns like a proc named * or info*, as info command does not have an -exact switch.


Category Glossary