Version 6 of Generating a unique name

Updated 2016-01-20 23:56:28 by pooryorick

Marco Maggi - The procedure presented in this page will generate a number of unique fully qualified names. All the names referes to entities in the "::tcl::tmp" namespace. Invoking the procedure with no arguments will return a name:

namespace import ::tcl::tmp::unique_name
set name [unique_name]

# $name -> ::tcl::tmp::123

giving variable names on the command line will cause the procedure to store a unique name in each of them:

namespace import ::tcl::tmp::unique_name
unique_name name1 name2 name3

# $name1 -> ::tcl::tmp::1
# $name2 -> ::tcl::tmp::2
# $name3 -> ::tcl::tmp::3

This procedure is useful when a script needs to store data in a static variable (a global or namespace variable), and to hand the variable name as argument to some procedure making the data available to other modules.

Nothing prevents us to use the generated names as procedure or namespace names, or simply as unique identifiers.


namespace eval ::tcl::tmp {
    variable        global_counter 0

    namespace export unique_name
}

proc tcl::tmp::unique_name { args } {
    variable        global_counter
    set pattern        "[namespace current]::%s" 
    set result        {}

    set num [llength $args]
    set num [expr {($num)? $num : 1}]

    for {set i 0} {$i < $num} {incr i} {
        set name [format $pattern [incr global_counter]]
        while {
            [info exists $name] ||
            [namespace exists $name] ||
            [llength [info commands $name]]
        } {
            set name [format $pattern [incr global_counter]]
        }
        lappend result $name
    }

    if { [llength $args] } {
        foreach varname $args name $result {
            uplevel set $varname $name
        }
    }
    return [lindex $result 0]
}

Ro: I do it like this: set name x[clock micro]


PYK 2016-01-20: Here's a snippet that produces a string of random letters, 24 in this case:

set id [if 1 "lindex [string repeat {[format %c [expr {entier(rand() * 26 + (int(rand()*10 > 4 ? 97 : 65)))}]]} 24]"]

And here is one that produces an a string of printable characters that, when interpreted as a base-68 number occupies approximately, but no more than 256 bits:

set id [if 1 "lindex [string repeat {[lindex {# % + - ^ = 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z} [expr {entier(rand() * 68)}]]} 42]"]