How tcl curly braces in ${variableName} is interpreted? - tcl

I am a newbie in TCL Programming. I was having confusion about curly braces, answer to this question tcl curly braces cleared most of my doubts.
I can understand $var, {var}, and {$var}, But recently I came across another use of curly braces, ${var}. How is this interpreted by TCL?
I have seen this is used when accessing variables in namespaces when namespaces name is in variable.
for example:
set x myNamespace ;#myNamespace is name of namespace
puts [set ${x}::var1] ;#var1 is variable in the namespace
It gives error when you don't use curly braces around 'x'.
And I also don't understand the difference between {a b c} and [list a b c], what is the difference in result of interpretation of these two commands by TCL interpretation.
elaborated explanation would be highly appreciated.

See rule 8 of the manual. It allows you to have variable names that might get mis-interpreted. For instance:
% set dotted.name 1
1
% puts $dotted.name
can't read "dotted": no such variable
% puts ${dotted.name}
1
Read section 8 carefully as it actually explains all this quite explicitly.
Update to answer edited question
In the example you provide using a namespace name in a variable you must consider section 8 part 1: a variable name includes letters, digits, underscores and namespace separators. This means that x::var1 is a valid variable name. So $x::var1 will attempt to dereference the var1 variable in the x namespace. As this is not what you meant, you must dereference your x variable separately. There are two ways to do this. You can either use the set command or the dollar operator.
set x myNamespace
puts [set ${x}::var1]
puts [set [set x]::var1]
The two puts statements are equivalent here with the second version showing an explicit separate pass to obtain the value of the x variable which is then substituted into the expression for the outer set command. The same occurs in the first version but just uses the grouping operator to restrict the effect of the dollar to the x variable name.

Related

apparent inconsistency read/write variable

I'm learning about Tcl just now. I've seen just a bit of it, I see for instance to create a variable (and initialize it) you can do
set varname value
I am familiarizing with the fact that basically everything is a string, such as "value" above, but "varname" gets kind of a special treatment I guess because of the "set" built-in function, so varname is not interpreted as a string but rather as a name.
I can later on access the value with $varname, and this is fine to me, it is used to specify varname is not to be considered as a string.
I'm now reading about lists and a couple commands make me a bit confused
set colors {"aqua" "maroon" "cyan"}
puts "list length is [llength $colors]"
lappend colors "purple"
So clearly "lappend" is another one of such functions like set that can interpret the first argument as a name and not a string, but then why didn't they make it llength the same (no need for $)?
I'm thinking that it's just a convention that, in general, when you "read" a variable you need the $ while you don't for "writing".
A different look at the question: what Tcl commands are appropriate for list literals?
It's valid to count the elements of a list literal:
llength {my dog has fleas}
But it doesn't make sense to append a new element to a literal
lappend {my dog has fleas} and ticks
(That is actually valid Tcl, but it sets the odd variable ${my dog has fleas})
this is more sensible:
set mydog {my dog has fleas}
lappend mydog and ticks
Names are strings. Or rather a string is a name because it is used as a name. And $ in Tcl means “read this variable right now”, unlike in some other languages where it really means “here is a variable name”.
The $blah syntax for reading from a variable is convenient syntax that approximately stands in for doing [set blah] (with just one argument). For simple names, they become the same bytecode, but the $… form doesn't handle all the weird edge cases (usually with generated names) that the other one does. If a command (such as set, lappend, unset or incr) takes a variable name, it's because it is going to write to that variable and it will typically be documented to take a varName (variable name, of course) or something like that. Things that just read the value (e.g., llength or lindex) will take the value directly and not the name of a variable, and it is up to the caller to provide the value using whatever they want, perhaps $blah or [call something].
In particular, if you have:
proc ListRangeBy {from to {by 1}} {
set result {}
for {set x $from} {$x <= $to} {incr x $by} {
lappend result $x
}
return $result
}
then you can do:
llength [ListRangeBy 3 77 8]
and
set listVar [ListRangeBy 3 77 8]
llength $listVar
and get exactly the same value out of the llength. The llength doesn't need to know anything special about what is going on.

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.

Printing multiple variables in tcl

I have to print multiple variables in a single puts like this
puts "$n1_$n2_$n3_$n4"
where n1 , n2 , n3 , n4 are 4 variables.
It wont print and will show error n1_ : no such variable
Expected output should be something like this (example)
01_abc_21_akdd
Variable names in Tcl can be any string in Tcl, there are no restrictions but if you want to use special characters (those not in the range of a-z, 0-9 and _, and letters in different languages depending on the platform and locale), you have to either brace the expression names or use other workarounds (like with the answer of Hoodiecrow).
What this means is that if you have a variable named abc.d, and if you use $abc.d, the Tcl engine will try to find the variable $abc because . is not a 'normal' character.
But if you have a variable named abc and use $abcd, or $abc_d, then the engine will start looking for the variables abcd or abc_d and not abc.
Because of this, you will have to use braces between the variable name for example:
${n1}
The reason why putting a backslash works is that \ is not a 'normal' character and after reading the above, it should be a little more obvious how things worked.
There are a few things that yet can go in variable names which don't need bracing and still mean something, except that something is 'special':
::: This is usually used for scoping purposes. For instance if you have a global variable named my_var, you can also use $::my_var to refer to it. Here :: tells Tcl that my_var is a global variable. Note that if there are more than two : in a row they will not add up:
% set ::y 5
5
% set ::::y
5
% set :::y
5
:: is usually used to define the namespace the variable is in. For example, $mine::var is a variable called var in the namespace with a name of mine.
(): These are used for arrays. $arr(key) is a variable with two parts: the array name arr and the key name key. Note: you can have an array named and a key named because...
% set () abc
abc
% puts $()
abc
% array get ""
{} abc
There might be some more, but those are the basics you could look out for.
Two other ways:
puts "${n1}_${n2}_${n3}_${n4}"
puts [format "%s_%s_%s_%s" $n1 $n2 $n3 $n4]
Documentation: format
(Note: the 'Hoodiecrow' mentioned in Jerry's answer is me, I used that nick earlier.)

Use of [list a b c] vs {a b c} when creating a list

What differences are there between creating a list in TCL using:
[list a b c]
vs
{a b c}
I'm by all means not an experienced TCL programmer, but the only difference I have encountered so far is when creating a list of multiple lines the first style requires using line continuation characters like:
[list \
a \
b \
c \
]
where this parses fine:
{
a
b
c
}
Are there any other differences? Which is considered better style or idiomatic?
It would appear that when creating a complex list with nested lists, the 2nd style is the only clean way to go.
The main difference is that using the list command makes it possible to use variables when defining the list. Notice the difference between these two:
% set foo 1
1
% set bar 2
2
% set list1 [list $foo $bar]
1 2
% set list2 {$foo $bar}
$foo $bar
Note that you can also use double quotes if you want:
% set list3 "$foo $bar"
1 2
It's important to note that of the two ways to build a list with variables, only using list is guaranteed to give you a proper list. Using quotes may or may not give you a list, depending on the contents of the variables. This isn't because Tcl is mysterious or random or buggy -- it's simply how tcl quoting works. With list you are asking tcl to construct a list with specific elements, in the others you're creating a string that looks like a list, but whether it can be treated like a list or not depends on the data in the string.
Here's an example where using quotes won't give you a list:
% set foo "{"
{
% set list4 "$foo $bar"
{ 2
% lindex $list4 0
unmatched open brace in list
... whereas using list will give you a proper list:
% set list5 [list $foo $bar]
\{ 2
% lindex $list5 0
{
It's important to know that the backslash appears only when tcl converts the list to a string for the purposes of printing the list -- the backslash isn't in the data, as you can see when you use lindex to fetch the value.
Are there any other differences? Which is considered better style or idiomatic?
In the case where you're after a list with just literals in it, no variable or command expansion or anything like that, using [list a b c] and {a b c} is exactly the same. They compile to identical bytecode in Tcl 8.6 (the push of a literal onto the result stack). There really is no difference at all.
Which is more idiomatic? I don't really know, to be honest. They are both idiomatic, and subject to individual preferences. The difference between them becomes important once you start using variable and command expansion, and then the question quickly ceases to be relevant.
That said, I mostly prefer to use {a b c}. It's more convenient when the literals are longer since I can break things over multiple lines without fussing around with backslash continuations. Other people will disagree with me; for them, the typing of [list…] reminds them strongly of what they intend to do with the data, and that's clearly of some mnemonic value.

Can we give array name with hyphen in TCL

I am declaring a array in TCL say
set JDSU-12-1(key) element
parray JDSU-12-1
I am getting error saying JDSU is not a array
Even simple puts statement is not working
% puts $JDSU-12-1(key)
can't read "JDSU": no such variable
Is there any way i can declare array name with hyphen. I know _ works in array but not sure about hyphen
You can use special characters in Tcl variable names. You need the braces for those though:
% puts ${JDSU-12-1(key)}
element
You can even use $:
% set \$word "Hello world" ;# Or set {$word} "Hello world"
% puts ${$word}
Hello world
EDIT: Some reference:
beedub.com (Emphasis mine)
The set command is used to assign a value to a variable. It takes two arguments: the first is the name of the variable and the second is the value. Variable names can be any length, and case is significant. In fact, you can use any character in a variable name.
You can use almost any character for the name of a variable in Tcl — the only restrictions relate to :: as that is a namespace separator, and ( as that is used for arrays — but the $ syntax is more restrictive; the name it accepts (without using the ${…} form) has to consist of just ASCII letters, ASCII digits, underscores or namespace separators. Dashes aren't on that list.
The standard (and simplest) way of reading from a variable with a “weird” name is to use set with only one argument, as that happily accepts any legal variable name at all:
puts "the element is '[set JDSU-12-1(key)]'"
However, if you're doing this a lot it is actually easier to make an alias to the (array) variable name:
upvar 0 JDSU-12-1 theArray
puts "the element is $theArray(key)"
That's exactly how parray does it, though it uses upvar 1 because it is aliasing to a variable in the calling scope and not in the current scope.
Although you can use such special characters, you can only use a few when you try to access variables with $varname.
To quote the relevant section from the manual:
$name
Name is the name of a scalar variable; the name is a sequence of one or more characters that are a letter, digit, underscore, or namespace separators (two or more colons). Letters and digits are only the standard ASCII ones (0-9, A-Z and a-z).
$name(index)
Name gives the name of an array variable and index gives the name of an element within that array. Name must contain only letters, digits, underscores, and namespace separators, and may be an empty string. Letters and digits are only the standard ASCII ones (0-9, A-Z and a-z). Command substitutions, variable substitutions, and backslash substitutions are performed on the characters of index.
${name}
Name is the name of a scalar variable or array element. It may contain any characters whatsoever except for close braces. It indicates an array element if name is in the form “arrayName(index)” where arrayName does not contain any open parenthesis characters, “(”, or close brace characters, “}”, and index can be any sequence of characters except for close brace characters. No further substitutions are performed during the parsing of name.
There may be any number of variable substitutions in a single word. Variable substitution is not performed on words enclosed in braces.
Note that variables may contain character sequences other than those listed above, but in that case other mechanisms must be used to access them (e.g., via the set command's single-argument form).
I want to empathis the last paragraph a bit:
You are always able to read any variable with set varname:
set JDSU-12-1(key) element
puts [set JDSU-12-1(key)]
Unlike the ${varname} access, you can substitute a part of the variable name (in your case the array key), the entire variable, while set k "key"; puts ${JDSU-12-1($k)} does not work.
You can easily do that:
set set-var "test"
while accessing so ${set-var}
Like in most other programming languages, TCL variable must be alphanumeric starting with letter (A to Z, or _). Hyphen or dash (-) is not permitted as part of variable name, otherwise it would be confused with arithmetic minus or subtraction: there would be no difference between $x-1 as variable with name "x-1" or $x-1 as variable x minus 1.
Try this :)
subst $\{[subst ${conn}](phan)\}
Which version are you working ??
my tcl works.
% set JDSU-12-1(key) element
element
% parray JDSU-12-1
JDSU-12-1(key) = element