Reputation: 3235
I just tried the following in tclsh:
proc pp {$ag} { puts hi}
pp whatever
To my surprise, this works fine! I had expected a syntax error because the proc argument is a variable. But it seems tcl takes it fine.
Then I experimented:
proc pp {$ag} { puts "hi $ag"}
pp whatever
and
proc pp {$ag} { puts "hi ${$ag}"}
pp whatever
I got error, can't read "ag": no such variable
.
This makes me wondering, can proc argument be variable? If not, why not error out in the first script?
Upvotes: 1
Views: 147
Reputation: 13252
The first case works because you never use the parameter to pp
.
When you invoke the proc
command, the text of the invocation is evaluated just like in any other command invocation. In all the above cases, the third argument (which will become the argument list of the pp
command) is is wrapped in braces, which means it won't be evaluated as a variable but as a string of three characters: "$ag" (i.e. the dollar sign is just a regular character here). This is not an error, and does work, just not the way you seem to expect it to.
It's a bit tricky to get the value of the parameter $ag
, though. This works:
proc pp {$ag} {puts "hi [set {$ag}]"}
The dollar notation is actually just syntactic sugar for the unary set
command. Sometimes the dollar notation won't work, and you need to fall back to an explicit set
.
This does work too, though:
proc pp {$ag} {puts "hi ${$ag}"}
So, in your invocations, the third argument to proc
isn't really a variable evaluation, it just looks like one. You can of course use an actual variable evaluation in the invocation of proc
:
set foo {bar baz}
proc qux $foo {puts $bar ; puts $baz}
qux abc def
# => abc
# => def
What the Tcl interpreter really sees here is:
proc qux {bar baz} {puts $bar ; puts $baz}
Or you can go really crazy:
set foa {proc qux}
set fob {bar}
lappend fob baz
set foc {puts $bar}
set fod "puts \$baz"
{*}$foa $fob [join [list $foc $fod] { ; }]
Which amounts to the same thing as the previous invocation of proc
. (If you don't believe me, try list {*}$foa $fob [join [list $foc $fod] { ; }]
)
This example just looks (and is) weird, but many times it's actually useful to construct new commands within your program, and in those cases it's really nice that the text used in the invocation of proc, like with any other command, is simply text that the evaluation rules of Tcl can be applied to. You can use any kinds of string or list operations on it and join up pieces of text from various sources, even user input (if you can trust it).
Documentation: Tcl evaluation rules including $ and {*}, join, lappend, list, proc, puts, set
Upvotes: 3