Single assignment variable

A single assignment variable is a variable that can be assigned a value no more than once. Single assignment variables can be used to emulate constants or to ensure correctness. In Tcl, you can prevent variables from being reassigned with trace.

Implementation

dbohdan 2015-11-05: The following is my implementation of single assignment variables.

Usage

    val foo 5
    puts $foo ;# prints "5"
    incr foo ;# error

or

   val foo
   # ...
   set foo 5
   puts $foo ;# prints "5"
   incr foo ;# error

Code

namespace eval ::singleAssignment {
    variable version 0.1.0
}
proc ::singleAssignment::traceAssigned {name1 name2 op} {
    error "variable \"$name1\" can't be modified"
}
proc ::singleAssignment::traceUnassigned {name1 name2 op} {
    uplevel 1 [list trace remove variable \
            $name1 {write unset} \::singleAssignment::traceUnassigned]
    uplevel 1 [list trace add variable \
            $name1 {write unset} \::singleAssignment::traceAssigned]
}
proc ::singleAssignment::val args {
    switch -exact -- [llength $args] {
        1 {
            lassign $args varName
        }
        2 {
            lassign $args varName value
        }
        default {
            set procName [dict get [info frame 0] proc]
            error "wrong # args: should be \"$procName name ?value?\""
        }
    }
    if {[uplevel 1 [list info exists $varName]]} {
        error "variable \"$varName\" is already set"
    }
    uplevel 1 [list trace add variable \
            $varName {write unset} ::singleAssignment::traceUnassigned]
    if {[info exists value]} {
        uplevel 1 [list set $varName $value]
    }
}
namespace path ::singleAssignment