Updated 2017-06-08 09:42:16 by dbohdan

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  edit

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