TCL subst or eval command is not working in my case .. - tcl

subst or eval command is not working in my case ..
% proc sum {a b} {
return [expr $a+$b]
}
%
% set a 1
1
% set b 2
2
% sum $a $b
3
%
% sum {$a} {$b}
can't use non-numeric string as operand of "+"
%
% subst [sum {$a} {$b}]
can't use non-numeric string as operand of "+" >>>>>>>>> Why i am unable to substitue the value
%
% eval [sum {$a} {$b}]
can't use non-numeric string as operand of "+" >>>>>>>>> Why i am unable to substitue the value
%
I want to know why the above cases are not working for me .. subst command should do the variable and command substitution . But why my variables are not substituting.
Can anyone Please Explain what is going on?

First, you do understand why “$a“ isn't a value you can add to? It's not a number at all. (I don't mean $a, the instruction to read from a variable and substitute it, I mean the string consisting of a $ followed by an a.)
When you put braces round things in Tcl, it means “don't do anything with this string at all; use it as-is”. Always. (Sometimes you're feeding that string into a command that evaluates, but not always.) When you put square brackets round things, it means evaluate that string as a script immediately and use the result of the script as the value to substitute. Always.
When you do:
subst [sum {$a} {$b}]
You need to understand that the call to sum is done while assembling the arguments to subst. That call produces an error, so the call to subst never happens. Similarly with the eval form you used.
If we use a somewhat less surprising form:
subst {sum {$a} {$b}}
Then you'll get this out: sum {1} {2}. subst doesn't understand the overall string as a script. On the other hand, with:
eval {sum {$a} {$b}}
In this case you get an error not from the eval as such, but rather from the fact that the call to sum inside is still erroneous.
I suppose you could do:
eval [subst {sum {$a} {$b}}]
But really don't. There's got to be a simpler and less error-prone way.

You put the square braces [] to the wrong place (resp. you even don't need them in the eval case). In the way you wrote the commands the sum {$a} {$b}] is evaluated before the subst or eval command could evaluate the contents of $a and $b.
Correct is:
eval sum {$a} {$b}
or
sum [subst {$a}] [subst {$b}]

You don't understand Tcl correctly.
subst takes a string and substitues all variables in it, right.
But you pass the result of sum {$a} {$b} into it, which fails.
So you could either subst each parameter before you call sum:
sum [subst {$a} {$b}]
Or modify the sum to do the evaluation for you:
proc sum {a b} {
uplevel 1 [list expr $a + $b]
}
expr does an own round of evaluation, this is why you usually pass a litteral string (enclosed with {}) to it, but in this case we actually use this fact. uplevel executes the command in the context of the caller.
If you call a command, Tcl will replace the variables before the actuall call is made, so maybe this snippet could help you to understand Tcl a little bit better:
set a pu
set b ts
$a$b "Hello World!"

Related

tcl scripts, struggling with [...] and [expr ...]

I can't understand how assignments and use of variables work in Tcl.
Namely:
If I do something like
set a 5
set b 10
and I do
set c [$a + $b]
Following what internet says:
You obtain the results of a command by placing the command in square
brackets ([]). This is the functional equivalent of the back single
quote (`) in sh programming, or using the return value of a function
in C.
So my statement should set c to 15, right?
If yes, what's the difference with
set c [expr $a + $b]
?
If no, what does that statement do?
Tcl's a really strict language at its core; it always follows the rules. For your case, we can therefore analyse it like this:
set c [$a + $b]
That's three words, set (i.e., the standard “write to a variable” command), c, and what we get from evaluating the contents of the brackets in [$a + $b]. That in turn is a script formed by a single command invocation with another three words, the contents of the a variable (5), +, and the contents of the b variable (10). That the values look like numbers is irrelevant: the rules are the same in all cases.
Since you probably haven't got a command called 5, that will give you an error. On the other hand, if you did this beforehand:
proc 5 {x y} {
return "flarblegarble fleek"
}
then your script would “work”, writing some (clearly defined) utter nonsense words into the c variable. If you want to evaluate a somewhat mathematical expression, you use the expr command; that's it's one job in life, to concatenate all its arguments (with a space between them) and evaluate the result as an expression using the documented little expression language that it understands.
You virtually always want to put braces around the expression, FWIW.
There are other ways to make what you wrote do what you expect, but don't do them. They're slow. OTOH, if you are willing to put the + first, you can make stuff go fast with minimum interference:
# Get extra commands available for Lisp-like math...
namespace path ::tcl::mathop
set c [+ $a $b]
If you're not a fan of Lisp-style prefix math, use expr. It's what most Tcl programmers do, after all.
set c [$a + $b]
Running the above command, you will get invalid command name "5" error message.
For mathematical operations, we should rely on expr only as Tcl treats everything as string.
set c [expr $a + $b]
In this case, the value of a and b is passed and addition is performed.
Here, it is always safe and recommended to brace the expressions as,
set c [expr {$a+$b}]
To avoid any possible surprises in the evaluation.
Update 1 :
In Tcl, everything is based on commands. It can a user-defined proc or existing built-in commands such as lindex. Using a bare-word of string will trigger a command call. Similarly, usage of [ and ] will also trigger the same.
In your case, $a replaced with the value of the variable a and since they are enclosed within square brackets, it triggers command call and since there is no command with the name 5, you are getting the error.

how lappend $varname1 $varname2 will be executed

I have searched for lappend $var1 $var2, but don't find any exact answer, how it will be executed.
% set a {a b c}
a b c
% set b {d e}
d e
% puts [lappend $c $b]
can't read "c": no such variable >>> here it throws error like variable not exist
% puts [lappend $a $b]
{d e} >>> here it doesn't throw any error, can someone explain it and how to print the value of $a, if $a is a new variable
% puts $$A
can't read "A": no such variable
% puts $$a
$a b c
% puts ${$a}
can't read "$a": no such variable
Tcl's got a two level syntax that it applies rigorously to everything. The first level is the Tcl generic syntax, which takes:
lappend $var1 $var2
and parses it out to three words: lappend, a word obtained by reading the variable var1, and a word obtained by reading the variable var2.
Then Tcl dispatches to the command named by the first word (lappend, a Tcl built-in) which applies command syntax handling. In the case of lappend, it's pretty simple: the first argument names a variable and the second and subsequent arguments are words to append to the list in the named variable.
In your case, the first argument that names a variable is obtained by reading another variable (var1) and the value to append to the list is coming from a variable (var2); a name like a b c d e is a legal variable name in Tcl, but it's really awkward to use. And the chance is very high that you don't want to write that: putting variable names in a variable is usually an indicator of confusing code. You can do it, but you hardly ever want to do it (except when you're using the variable name with upvar). You probably really meant to write:
lappend var1 $var2
Tcl is very exact about the distinction between variable names and variable contents. The $ is not decorative! It's there to say “read this variable, right now”, and $var1 is virtually equivalent to [set var1] in semantic terms. (The $ shorthand was later, a Tcl 2.0 feature from way back in the day!)
Tcl also doesn't allow double-dereferencing with $$vrbl. In the rare cases you need it, you do [set $vrbl]. And if you do that, you probably should immediately see if you can use an array instead as that's typically a better choice…
lappend's first parameter is a variable name, not a value. Therefore, in general, it should be:
lappend var1 $var2
where both var1 and var2 are list variables. See the Tcl lappend man page for more details.

variable substitution - each value becomes an argument

When a variable is substituted and the value is a list, is it possible that each value of the list is regarded as one argument?
Here is an example code:
set a "-nonewline hi"
puts $a
What I really want is after the substitution, the puts command becomes puts -nonewline hi instead of puts "-nonewline hi".
Is it possible?
Yes, you can use something like this:
puts {*}$a
In versions prior to 8.5, you would have to use eval:
eval puts $a

Can proc argument be variable

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?
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

Getting unevaluated tcl arguments

What I want to do is parse an argument to a tcl proc as a string without any evaluation.
For example if I had a trivial proc that just prints out it's arguments:
proc test { args } {
puts "the args are $args"
}
What I'd like to do is call it with:
test [list [expr 1+1] [expr 2+2]]
And NOT have tcl evaluate the [list [expr 1+1] [expr 2+2]]. Or even if it evaluated
it I'd still like to have the original command line. Thus with the trivial "test"
proc above I'd like to be able to return:
the args are [list [expr 1+1] [expr 2+2]]
Is this possible in tcl 8.4?
You cannot do this with Tcl 8.4 (and before); the language design makes this impossible. The fix is to pass in arguments unevaluated (and enclosed in braces). You can then print them however you like. To get their evaluated form, you need to do this inside your procedure:
set evaluated_x [uplevel 1 [list subst $unevaluated_x]]
That's more than a bit messy!
If you were using Tcl 8.5, you'd have another alternative:
set calling_code [dict get [info frame -1] cmd]
The info frame -1 gets a dictionary holding a description of the current command in the context that called the current procedure, and its cmd key is the actual command string prior to substitution rules being applied. That should be about what you want (though be aware that it includes the command name itself).
This is not available for 8.4, nor will it ever be backported. You might want to upgrade!
When passing the arguments into test, enclose them in braces, e.g.:
test {[list [expr 1+1] [expr 2+2]]}