You're confusing array's with lists here.
In tcl, you cannot pass arrays into or return them from functions. Also, tcl uses the term "arrays" for what C++ calls "maps" or Perl and Ruby call "hashes" or what Javascript calls "objects". The term comes from the fact that all these things are generically known as "associative arrays" in computer science. So "arrays" in tcl are key-value pairs, not sequences of data.
Arrays don't normally degenerate into values (or what a seasoned tcl programmer would call "strings"). Therefore this:
array set tcArrayName {$fileName $tcSpec};
return $tcArrayName;
generates a syntax error:
can't read "tcArrayName": variable is array
You can actually degenerate the contents of an array into a value that you can then return. But you have to do it manually via the [array get]
command:
return [array get tcArrayName]
The above command will return the content of the tcArrayName
array in the form of a two element list:
"$fileName $tcSpec"
which also happens to be a string. And that's the actual string: the character '$' followed by the characters 'f', 'i', 'l', 'e', 'N', 'a', 'm', 'e' etc. Not the filename and the concatenated item name and item id. The literal string "$fileName $tcSpec".
That's because you've used the {}
grouping in this line of code:
array set tcArrayName {$fileName $tcSpec}
In tcl, {xxx}
behaves the same way 'xxx'
does in Perl. Basically its a literal string that does not get substituted. If you want tcl to do $
substitution then you need to use ""
grouping:
array set tcArrayName "$fileName $tcSpec"
But this is fragile because if fileName
contains spaces then it would break the code. A more robust way to do this is:
array set tcArrayName [list $fileName $tcSpec]
But using an array
in this case is a bit redundant since all you're doing is initialising it with a key-value list (also known as a dict
in more modern versions of tcl. BTW, what version of tcl are you using?) and then immediately discarding it and returning it's content as a key-value list.
Why not simply return that key-value list:
proc B {fileID} {
set fileName [::getFileName $fileID]; # getFileName returns filename from fileid
set tcName "[set ItemName]_[set ItemId]"
return [list $fileName $tcSpec]
}
But we're still not in the clear. If you try to execute B
you'll see this error:
can't read "ItemName": no such variable
That's because tcl does not import global variables into functions by default. As such the variables ItemName
and ItemId
don't exist in B
. You either need to import it explicitly via the global
command:
proc B {fileID} {
global ItemName
global ItemId
# ...
}
or access it via the global namespace using a fully qualified variable name:
set tcName "[set ::ItemName]_[set ::ItemId]"
So B
should look like this:
proc B {fileID} {
set fileName [::getFileName $fileID]; # getFileName returns filename from fileid
set tcName "[set ::ItemName]_[set ::ItemId]"
return [list $fileName $tcSpec]
}
That's B
taken care of but A
has some problems as well:
can't read "file1": no such variable
We need to modify it a bit to access the variable file1
:
proc A {} {
set lst_A [list];
if {true} { ;# assuming that there will be a valid condition here
lappend lst_A [::B $::file1];
} else {
foreach id $allId {
lappend lst_A [::B $id];
}
}
return $lst_A;
}
This should work as you expect.
If you want a little speed up when you use the key-value list then you should really read up on dicts
. As is, dicts won't affect the code given above but it does affect the code calling A
. If you plan on using dicts then you can replace the lappend
call above with dict append
. But older versions of tcl don't have dicts.