curlywei
curlywei

Reputation: 720

Pass global variable into function in tclsh

I defined 3 (global) constant for string first:

set kColorGBegin "\x1b\[1;32m"
set kColorRBegin "\x1b\[1;31m"
set ColorEnd  "\x1b\[0m"

then I create 2 functions rendering and printing input string:

proc r_puts {strs} {
  puts "${kColorRBegin} ${strs} ${ColorEnd}"
}
proc g_puts {strs} {
  puts "${kColorGBegin} ${strs} ${ColorEnd}"
}

and invoke:

[r_puts "foo"]
[g_puts "bar"]

I got there error message when run this program:

can't read "kColorRBegin": no such variable
    while executing
"puts "${kColorRBegin} ${strs} ${ColorEnd}""
    (procedure "r_puts" line 2)
    invoked from within
"r_puts "foo""
    invoked from within
"[r_puts "foo"]"
    (file "./t.tcl" line 14)

How do I solve it?


Full code here:

set kColorGBegin "\x1b\[1;32m"
set kColorRBegin "\x1b\[1;31m"
set ColorEnd  "\x1b\[0m"

proc g_puts {strs} {
  puts "${kColorGBegin} ${strs} ${ColorEnd}"
}

proc r_puts {strs} {
  puts "${kColorRBegin} ${strs} ${ColorEnd}"
}

[r_puts "foo"]
[g_puts "bar"]

Upvotes: 1

Views: 462

Answers (2)

glenn jackman
glenn jackman

Reputation: 246942

Don't put braces around the calls to r_puts and g_puts: that will invoke the procs as command substitutions, replace the command substitution with the results, and then try to execute the results as commands.

Demo:

$ tclsh
% proc r_puts {msg} {puts $msg}
% r_puts hello
hello
% [r_puts hello]
hello
ambiguous command name "": after append apply ...

Upvotes: 1

Donal Fellows
Donal Fellows

Reputation: 137627

In Tcl, all variables in procedures are local to the procedure unless you say otherwise in that procedure; having to be explicit about this saves all sorts of trouble in the long run. (Things are slightly more complicated in object methods, but you're not dealing with those, and even then they only get complicated when you explicitly ask for it.) This is done most often using the global command inside the procedure, like this:

proc r_puts {strs} {
    global kColorRBegin ColorEnd
    puts "${kColorRBegin} ${strs} ${ColorEnd}"
}
proc g_puts {strs} {
    global kColorGBegin ColorEnd
    puts "${kColorGBegin} ${strs} ${ColorEnd}"
}

You'll probably want to omit the spaces between the variable substitutions.


The other commands used for this are: variable (usually when working with small numbers of variables in a namespace other than the global one), upvar (when working with variables passed by name from a caller), and namespace upvar (when working with many variables in a namespace other than the global one).

Upvotes: 1

Related Questions