Version 3 of constants

Updated 2001-11-22 23:21:15

How do you create constants in Tcl programs? There are, of course, several ways.


procedure constants

Create a procedure for each constant, which returns the value.

  proc FLAG1 {} { return 0x0001 }

You then access the constant by calling the procedure, like [FLAG1]. This is easy to code, but gets clumsy when you have lots of constants. Another possibility is to use an array in one constant function, but this is fairly inflexible.

  proc CONST { key } {
    array set constant {
        FLAG1  0x001
        FLAG2  0x002
        PI  3.14159
    }
    return $constant($key)
  }

readonly trace

Brent Welch suggests using write variable traces to implement readonly variables. But since the write trace fires after the variable value has changed, you need to keep a cache of the original value somewhere.

George Howlett made a suggestion at a recent Tcl conference tutorial that read traces are your friend. He suggested a couple of very flexible procedures. (According to Don Porter's c.l.t. post)

  % proc _constant_read_trace {val name1 name2 ops} {
      upvar $name1 var
      set var $val
  }
  % proc constant {varName value} {
      uplevel [list trace variable $varName r [list _constant_read_trace $value]]
  }
  % constant PI 3.14159
  % set PI
  3.14159
  % set PI 3; # Only in Indiana :)
  3
  % set PI
  3.14159

RS: Slightly modified the above, so attempts to vary a constant raise an error (it probably was one ;-):

  proc _constant_trace {val name1 name2 ops} {
      upvar $name1 var
     if {$ops=="w"} {
        return -code error "constant $val may not be changed"
     }
      set var $val
  }
  proc constant {varName value} {
      uplevel [list trace variable $varName rw [list _constant_trace $value]]
  }
 % set PI 1.23
 can't set "PI": constant 3.14159 may not be changed

RS again: This raises no error, but keeps a constant with minimal code:

 proc const {name value} {
   uplevel 1 [list set $name $value]
   uplevel 1 [list trace var $name w "set $name [list $value];#" ]
 }

Karl Lehenbauer, I think, gets credit for one invention of read-only variables [cite references].