Version 18 of init

Updated 2013-06-25 18:18:54 by Larry

Larry Smith - This page supersedes getparams. It is the latest and most elegant version of my named parameter parsing routine. It takes an option -using <overrides> parameter, and a list of vars and default values. First it initializes the variables to their given defaults in the calling scope, then it parses the overrides argument and sets those "-var val" pairs in the calling scope. In essence, it declares all your local variables and then allows them to be set by command-line switches. But it will not permit vars mentioned in the overrides being set unless they appear in the vars list. This prevents the caller from setting local or meaningless variables.

Init returns a list of -var val pairs for all the vars it did not recognize. This allows you to pass through things for later processing.

 # init.tcl
 # Takes a list of variable-value pairs and creates and
 # initializes the former with the latter in the calling
 # context.

 proc init {args} {
  upvar args arglist
  set args [regsub -all {\#[[:print:]]*} $args "\r"]
  if {[llength $args]==0} ^
  if {[llength $args]==1} {eval set args $args}
  # first pass - args on command line
  set vars {}
  foreach {var val} $args {
    uplevel set $var \{$val\}
    lappend vars $var
  set i 0
  foreach var $vars {
    set i [lsearch $arglist -$var]
    if {$i != -1} {
      set arglist [lreplace $arglist $i $i]
      if {$i <= [llength $arglist]} {
        set val [lindex $arglist $i]
        set arglist [lreplace $arglist $i $i]
      } else {
        set val 1
    } else {
      incr i; continue
    if {[string index $val 0] eq "&"} {
      set val [string range $val 1 end]
      uplevel unset $var
      uplevel upvar $val $var
    } else {
      uplevel 1 set $var \{$val\}
  set arglist [string trim $arglist]


 proc foo { args } {
   init a 1 b 2 c 3
   puts "$a, $b, $c"

 foo -a 3

prints "3, 2, 3"

 foo -b 1 -c 4

prints "1, 1, 4"

 foo -b 1 -d 5

prints "1, 1, 3" and the attempt to set a var "d" is ignored (it did not appear in the init list).

You can also brace arguments:

 foo -a 5 -b 2

can also be expressed as:

 foo {
   -a 5
   -b 2

The new feature - adding references to Tcl!

 proc changevar {args} {
  init var ""
  set var 3

 set foo 1
 changevar -var &foo
 puts "foo is now $foo"

This sets the global "foo" to 3.

init is now also much more conservative in how it handles args. In particular, it now only sets the variables mentioned in the command line - a call of "init a 1 b 2" not only set just a and b, it also only removes -a x and -b x in the args list as well. This leaves the list intact for multiple calls to init depending on when and where in your code you decide you need another arg.

proc demo {args} {

  init a 1 b 2

  # la-de-da
  # oops - we need c as well!
  init c 3
  puts "now we have $c"


demo -a 56 -b 27 -c 92

This is very helpful for evaluating code - the code that follows the "oops" line above is often code from some other source (even passed as an argument itself) with its own requirement for parameters. Now you can use this code and get parameters for it the same way as you would for a proc. This is extremely handy for dealing with code coming out of databases or the like.