Reputation: 1295
I have two questions on the behavior of Tcl on single-element lists. As stated in https://stackoverflow.com/a/36891015/3852630 and discussed in https://wiki.tcl-lang.org/page/list (section "Single-word Lists vs non-list value"), braces (curly brackets) around a single element are removed.
I'm writing an application where this is problematic, so I wonder how to prevent this behavior and keep the braces also for single-element lists.
My first question is: Where in the Tcl interpreter is this brace-removal taking place? Are these specific commands, or is this taking place deeper in the interpreter?
list
seems to be one command where brace-removal happens:
% list a b
a b
% list a {b}
a b
% list a {{b}}
a {{b}}
but it doesn't happen in puts
:
% puts "a b"
a b
% puts "a {b}"
a {b}
% puts "a {{b}}"
a {{b}}
Actually, I think the behavior is pretty inconsistent in list
:
% set l {a {b}}
a {b}
% set l [list a [list b]]
a b
My second question is: How can I prevent this brace-removal?
Thanks for your help!
Upvotes: 0
Views: 552
Reputation: 137567
The braces are a quoting mechanism in lists and the Tcl interpreter in general. The list formatting engine preferentially avoids all quoting, otherwise uses braces if it must quote and can do so, and will fall back to backslashes if there's no other way. It never chooses to use double quotes; in theory we could change that in the future, but in practice that's extremely unlikely.
In this case:
list a {b}
the braces around b
are Tcl script quotes and the list
command does not see them at all. When we make a list with:
list a {{b}}
we now have a second element that has braces in its value; we can see this from:
set theValue [ list a {{b}} ]
puts [lindex $theValue 1]
In this case:
puts "a {b}"
you are doing something different: you're putting double quotes around things. That value is a list too, albeit not one in canonical form:
set theValue "a {b}"
puts [lindex $theValue 1]
The space of non-canonical lists is quite large, but you're not usually recommended to explore it in detail as changes (other than altering one type of whitespace separator to another, such as a single-space to a newline-and-indent to make a nicer looking literal list in your source code) are a bit difficult to get right. If you're constructing a list from non-constant bits, use the standard commands for doing so as they handle all the tricky edge cases correctly. (Non-canonical lists are those that parse as lists but which you'll never get out of the list
command and its friends like lrange
and lappend
.)
If you're trying to render a list and the default canonical representation is not enough, try this (assuming you've got Tcl 8.6):
puts [string cat "\{" [join $theListToRender "\} \{"] "\}"]
That'll change an input list of, say, a b
to {a} {b}
. In all but the most horrible of cases (those with unbalanced braces being the main ones; that's when Tcl's built in list quoting switches to producing an infestation of ugly backslashes) it will produce non-canonical but valid lists. The other form you appear to want isn't something that Tcl knows how to produce by default: the fact that one argument was braced and the other not is actively gone by the time it arrives at the renderer. (The literal b
and {b}
in your examples actually end up as identical bytecode including identical literal values.)
Upvotes: 2