Version 9 of Tcl warts

Updated 2010-07-19 22:08:02 by AMG

Purpose: to detail some of the places where interacting with Tcl leads one to frustration, confusion, aggrevation, anger, hatred, ... (you get the idea...)


namespace: The concept is good, but the execution is flawed, especially if you're doing anything object-oriented. Which is kind of ironic, given that (AFAIK) namespace were created to support OO, specifically incr Tcl. The implementation has C++'s fingerprints all over the syntax. Tcl is many things, but C++ is not one of them. The two don't fit well together.

A problem that I keep running into is that I don't typically use the global scope operator :: for objects at global scope, so there's usually a string inequality between what I'm typing and the value of $self, $this, [self], whatever the OO system is using. And if you try and compose object names by combining object names, you get spurious ::'s lying around in the middle of names, which makes Tcl very unhappy.

glob: the need to somehow quote the glob {} combination so that one gets the quotes passed on to glob. Use quotation marks (") or braces around the arguments to get them past the parser.

Regular expressions: a similar problem - the need to quote arguments appropriately so that various regular expression metas make it through the tcl parsing.

Tcl comments: Why can I not place unmatched braces in Tcl comments

Tcl hashes vs arrays: Sometimes people attempt to simulate 2 or more dimensions of arrays using the Tcl associated hashes (aka tcl arrays). The gotcha here is that because the array index is a string, white space is significant.

 $ set a1(1,2) abc
 abc
 $ puts $a1( 1,2)
 can't read "a1( 1,2)": no such element in array
 while evaluating {puts $a1( 1,2)}

Another gotcha here is trying to set arrays with white space:

 $ set a1( 1,2) abc
 wrong # args: should be "set varName ?newValue?"
 while evaluating {set a1( 1,2) abc}

You need to use quotes if you are putting space into that variable.

AMG: Use nested dicts. Or, generate the array index using "[list $row $col]" instead of "$row,$col". In all cases, be aware that $row and $col are general strings, not numbers.


Easily Tcl's most undeniable blemish: exec's brokenness in not directly allowing < or > as leading characters in arguments. [open |] has the same problem.

{*} addresses another blemish, which was previously handled using eval and precise list manipulation.

[inconsistencies in names in library]


LV Shoot, exec doesn't allow | as a leading character in an argument either. And - as the leading character in an argument can cause problems, and so on...

On the other hand, if you are talking about using < or > as the leading character in a file name, you solve that problem in the same way you solve the others - make certain it isn't a relative path name:

 % exec ls ./>stuff
 ./>stuff: No such file or directory

So it is doable.

AMG: "Quoting" (disabling special interpretation) filenames with ./ works fine, but there's no way to do it for non-filenames, where the external command absolutely must receive <, >, or | as the first character of an argument. Since sh internally handles these characters, it supports quoting them. Tcl doesn't handle these characters internally, so it falls to exec to do quoting, but exec doesn't. Adding quoting to exec would be highly unfortunate, considering how it would have to be used in practice. For now, if you absolutely must use <, >, or | as the first character of an argument, construct your command pipeline as a suitably-quoted argument to "sh -c".

exec sh -c {echo "<urgent!!>"}

But watch out that the !'s don't get interpreted as history substitution markers!

Hmm, I bet there's a security issue here. If arbitrary untrusted user-provided data gets passed as the argument to an external program, what's to stop the user from passing ">/etc/passwd" and hosing the system?

Perhaps what's needed is an alternative to exec that doesn't use inband signaling metacharacter sequences to configure command pipelines. For example, alternate between commands, each of which would be one list-formatted argument, and options describing how the commands are tied together. This can get complicated, so maybe justify the complexity of the syntax by also making it more powerful. Consider allowing for more flexible pipelines that branch different file descriptors around into a tree structure. E.g. some program is run, its stdout gets piped to the stdin of "tee log", its stderr gets piped to the stdin of "tee errors", and the stdout of each tee get combined again to be the stdout of the whole pipeline.


AMG: These quoting-related warts arise from conflicts between the commands' little languages and the core language of Tcl defined in the dodekalogue. The same is true for sh, e.g. you need to quote wildcards in the -name option to the find program, or else the shell will expand them prematurely.