47 comments

[ 4.0 ms ] story [ 102 ms ] thread
Tcl is pretty cool as a historical curio but boy, every time I go back and look at old tcl code, even stuff that I wrote, it takes forever to wrap my head around the syntax.

I'm not sure why I'd reach for Tcl today when lua exists.

Tcl is highly configurable because of its simple syntax and homoiconicity. It can be stripped down to be non-Turing complete for configuration files and then built back up with custom commands to suit ones needs.
The syntax of Tcl is bog-simple, and it’s entire operational description fits in a simple man page[0]. The flexibility can certainly be abused, though that’s not strictly the fault of Tcl.

[0] https://www.tcl-lang.org/man/tcl8.6/TclCmd/Tcl.htm

> The syntax of Tcl is bog-simple, and it’s entire operational description fits in a simple man page[0].

given a problem of fixed complexity, the simpler the language, the harder will the implementation of this problem have to be

Yep. Languages with a simplistic syntax (and a simplistic paradigm) make writing compilers for those languages easy, but they do not make creating programs in the languages easy. We can think of Lisp, or even more of Forth. It is also a common characteristic of "esoteric" languages: providing very little syntax, very few keywords, instructions and ready-built features, is an ingredient of their recipe for obfuscation.
Why is it hard to make programs in lisp? Especially in something like Common Lisp?
Not sure how to respond - you’re not necessarily wrong, but Tcl is also not Brainfuck[0]. The GP was indicating:

> it takes forever to wrap my head around the syntax.

... which (from observation) is often from second-guessing or overthinking the rules.

[0] https://en.wikipedia.org/wiki/Brainfuck

(comment deleted)
> I'm not sure why I'd reach for Tcl today when lua exists.

Regular syntax, for one thing. Command-oriented sensibility, too.

Are TCL scripts still necessary for some VLSI software stacks?
Yes. A typical SoC is assembled using thousands of lines of TCL to drive the various EDA tools that are involved in the design process.
Yep, it's the de facto automation language for IC design and EDA. I use it everyday. It's not a language I'd use for anything else, but as almost all EDA tools embed it, you have to learn it to be productive in the digital EE world
Yeah. Most Cadence and Synopsys tools for synthesis, place and route, static timing analysis, all have Tcl as the built in scripting language.
Arguments against Tcl like:

https://vanderburg.org/old_pages/Tcl/war/0000.html

aside, I found Tcl/Tk along with with the extension Expect:

https://en.wikipedia.org/wiki/Expect

to be a powerful way to do automation. In the '90s, I automated a process of migrating data from a mainframe to Unix workstations using a Tk GUI run by end users which generated Tcl/Expect scripts to download, convert, and verify massive amount of files in a batch.

Heck....I just used Tcl/Expect to automate 1000s of transactions in one of our legacy systems. I tried a number of expect implementations (python, go, java), but found them all lacking or overly complicated compared to the original Expect.

If you need to automate old terminal apps, you really can't do any better at the moment.

Most of those arguments are out of date. Tcl has evolved significantly since 94. It's never going to win on raw performance, but for its intended use cases, interpreter performance doesn't have to be best in class.
I haven't written any Tcl/Tk/Expect recently. It is interesting to know they are still being used, thanks for the updates. Expect was also quite useful for testing command-line applications. Even back then, RMS's arguments may or may not have applied to what he was doing, but our department got a lot of use out of Tcl for our sys admin work. We had many new-hires at the time, some without much CS background, and we found they could acquire and become productive in Tcl quickly, which was important in meeting our schedule.
(comment deleted)
Tcl is one of my favorite scripting languages to work in. It’s wonderful in the simplicity of the core language and how you can write things that act like keywords as just pure Tcl. I’d love to see Tcl gain some modern sensibilities like closures, the ability to run a destructor when a variable falls out of scope or is deleted, nested variable scopes within a proc, etc.
> the ability to run a destructor when a variable falls out of scope or is deleted

This has been present for many years (for how long I do not know). Look up the "trace add variable ..." command.

> nested variable scopes within a proc,

This is possible (if a bit clunky) with Tcl of at least V8.5 vintage by using the "apply" command. According to this page (https://stackoverflow.com/questions/1478510/when-was-tcl-v8-...) 8.5 was first released Dec. 20, 2007, so this one has been possible for 13 years.

I wrote a "defer" command in Tcl using this !
> This has been present for many years (for how long I do not know). Look up the "trace add variable ..." command.

I suppose I should have been more explicit. I want to know when the value the variable holds goes away, so I can clean up the resources that value represents (for example, if the value names a unique namespace that groups related values, I want to delete the namespace once the name no longer exists).

I double-checked Tcl 8.6’s OO stuff and it says you need to explicitly destroy objects, they won’t be destroyed simply because they went out of scope, so even the core language isn’t doing this.

> This is possible (if a bit clunky) with Tcl of at least V8.5 vintage by using the "apply" command.

apply does not create a nested scope. It runs the code in the global namespace (or some other namespace you specify), so it has no access to the current scope unless you use upvar within the lambda. What I want is nested variable scopes that don’t require upvar to access the outer scopes.

I recently started learning Tcl for the heck of it and am surprised by what a nice little language it is and that it doesn't get more publicity. It's true that it's not great for working with numbers or complex data structures, but it's a really nice language for "plumbing", and is still in active development. The last few releases have added support for tail-call recursion, "coroutines", and native dictionaries. It's had a bytecode compiler for like 20 years, so it's not as slow as it used to be.

As far as complaints about the syntax being weird: It's far more consistent than Algol descendants in that everything is a string, much like everything in Lisp is a list. You don't have to learn a bunch of different syntactic constructs, everything is a string, and every string is a space-delimited list, and can be interpreted as a command. The hardest part of the language is the quoting rules, which the documentation affectionately refers to as "quoting hell". Once you wrap your head around that, everything becomes clear. The standard library is pretty easy to learn, and the documentation is good.

Check it out.

Also the community is quirky fun, I remember finding a lot of esoteric implementation of whatever cs/lisp concept I could think of.

These kind of communities are fun.

The core developers are very thoughtful bunch on what gets into Tcl as well. It's nice to watch the back and forth traffic.
TCL (pronounced Tickl, if you’re still still saying T-C-L) is one of my absolute faves. Using TK from the command line is so easy / fast. And...as a language, it really helps to teach you important concepts. SQLite and Redis both emerge from TCL. The best place to see it in action is the SQLite codebase. Highly recommended.
I've recently spent some time experimenting with Tcl, and I've developed some affection for it, but what tripped me up is that "everything is a string" means that Tcl is one of the few truly weakly typed languages. This Tcl notation:

    {a b}
might represent any of the following data structures in JSON notation:

    "a b"
    ["a", "b"]
    [["a"], ["b"]]
    {"a": "b"}
    {"a": ["b"]}
This can make reading some Tcl code quite a puzzle.
Good observation. Tcl's

  {a b}
also represents something not possible in JSON:

  {["a"]: ["b"]}
The string

  a
can be treated as

  "a", ["a"], [["a"]], [[["a"]]], ...
by list operations.
Technically, Tcl's internal type system is that all other value types are subtypes of string, universally serializable to string, and will correctly round-trip through string. But it also means that you can type-pun stuff if you want; it just costs time.

FWIW, the best handling I know of JSON in Tcl is the rl_json package (https://github.com/RubyLane/rl_json) which essentially makes JSON into what works like a native Tcl value type.

Many earthquake engineers and researchers are all too familiar with Tcl, because for years the preeminent structural analysis tool OpenSees [1] required Tcl scripts to use/run. Just in the last few years was it forked to python.

https://opensees.berkeley.edu/OpenSees/home/about.php

My favorite Tcl trick is a single-line template file processing system.

    puts [ subst [ read [ open [ lindex $argv 0 ] ] ] ] 
(Hint: `subst` applies Tcl's string substitution function, which substitutes variables like $varname and Tcl commands enclosed in square brackets. So, this one line program can be used as a templating system that is somewhat like PHP or eRuby.)
The article mentions how prominent Tcl is in EDA, but the other big user I'm aware of is as the scripting tool of choice for Cisco's IOS (as of 10 years ago, not sure if that's still true today).
(comment deleted)
Having used Tcl, one improvement it could benefit from is making debug a first-class citizen.

(At least the versions I used) do not print the exact line number if something fails. They print top of the enclosing loop. Super annoying.

Which versions did you use? With modern Tcl (8.6) you get exact line numbers:

   $ tclsh test
   line 1
   line 2
   line 3
   error here
       while executing
   "error "error here""
       (procedure "test-error" line 5)
       invoked from within
   "test-error"
       (file "ttttt" line 9)
Where the contents of "test" were:

   $ cat -n ttttt
     1  proc test-error {} {
     2    puts "line 1"
     3    puts "line 2"
     4    puts "line 3"
     5    error "error here"
     6    puts "line 4"
     7  }
     8  
     9  test-error
Line 5 and line 9 match up exactly.
Huh. You're right. I use 8.6. I guess then it's the "feature" of apps that I use which embed Tcl. Maybe I will file a ticket because it's frustrating as hell when we had to port scripts from one program's scripting system to its successor. Thankfully interns were at our disposal ;)
When is using TCL the right choice? For example ruby is a good choice for building a web app and fortan is great for science. How is TCL typically used?
The last paragraph answered my question:

"Tcl continues to be heavily used as an embedded scripting language, a domain where it still seems to be the best alternative"

I've mainly see it used in HDL tooling to glue disparate tools together.

That being said, it grew on me as a general scripting language kind of generally in the same space as Perl.

Just made a tcl script yesterday for some FPGA stuff. Not a bad little language.