The task package

Marco Maggi (Package updated on June 2003) This package provides the ability to create a set of variables and restrict access to them to a set of procedures. This is similar to the creation of an object or a namespace used to hold variables private for an object instance.

All the procedures are located in the "task" namespace.


[constructor varname ?...?] - Initialiases a new task and returns the task identifier. The arguments are variable names that are linked to the scope of the caller. This procedure behaves exactly like [global]: variables are not created, just linked to the current scope. Using the empty string as variable name will lead to undefined behaviour. "varname" is the public name of the variable, the real name is the one of a variable in a private namespace.

[destructor task] - Deletes all the task specific data associated to the task identified by "task" (one more task and I shot myself). After this invocation the task (bang!) identifier "task" is no longer valid. Returns the empty string.

[global task varname ?varname ...?] - Links task-specific global variables in the scope of the caller. This procedure behaves exactly like [global]: variables are not created, just linked to the current scope. Returns the empty string.

[globname task varname] - Returns the real name of a task global variable. This can be used, for example, in a call to [vwait].

[globset task varname value] - Stores a new value in a non-array variable.

[globget task varname] - Returns the value in a non-array variable.


As simple usage example take a look at the following code:

  proc begin { task working_directory } {
      set task [task::constructor data pwd]
      set data 123
      set pwd ...
  }
  proc routine { task args } {
      task::global $task data

      cd [task::globget $task pwd]
      ...
      set data ...
      ...
  }
  proc end { task } {
      task::global $task data

      # do something with "$data"

      task::destructor $task
      return
  }

  begin ::task
  routine ::task
  end ::task

The package code follows.


 namespace eval task {
     namespace export \[a-z\]*
     variable counter 0
     variable ns [namespace current]
     variable map
     array set map {}
     namespace eval tmp {}
 }

 proc task::constructor { args } {
    variable        counter
    variable        map
    variable        ns

    while { [info exists map([incr counter])] } {}
    set map([set token $counter]) {}
    foreach varname $args {
        while { [info exists [set n ${ns}::tmp::[incr counter]]] } {}
        uplevel [list upvar [set map($token:$varname) $n] $varname]
    }
    return $token
 }

 proc task::destructor { token } {
    variable        map
    # Some variables may be unexistent, only registered, so we use
    #"-nocomplain". 
    foreach k [array names map $token:*] {
        unset -nocomplain -- $map($k)
        unset map($k)
    }
    unset map($token)
    return
 }

 proc task::global { token varname args } {
    variable        map

    uplevel [list upvar $map($token:$varname) $varname]
    foreach varname $args {
        uplevel [list upvar $map($token:$varname) $varname]
    }
    return
 }

 proc task::globname { token varname } {
    variable        map
    return $map($token:$varname)
 }

 proc task::globset { token varname value } {
    variable        map
    set $map($token:$varname) $value
    return
 }

 proc task::globget { token varname } {
    variable        map
    return [set $map($token:$varname)]
 }