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.
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.
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
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.
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.
> 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.
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.
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.
(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).
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)
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?
Ironically while Rails might have done the headlines for Ruby, almost a decade before, we were using many of the same ideas in AOLServer, Vignette, Safelayer (our own implementation back in the .com wave)
47 comments
[ 4.0 ms ] story [ 102 ms ] threadI'm not sure why I'd reach for Tcl today when lua exists.
[0] https://www.tcl-lang.org/man/tcl8.6/TclCmd/Tcl.htm
given a problem of fixed complexity, the simpler the language, the harder will the implementation of this problem have to be
There is a talk on youtube about it I know
> 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
Regular syntax, for one thing. Command-oriented sensibility, too.
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.
If you need to automate old terminal apps, you really can't do any better at the moment.
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 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.
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.
These kind of communities are fun.
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.
https://opensees.berkeley.edu/OpenSees/home/about.php
(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.
"Tcl continues to be heavily used as an embedded scripting language, a domain where it still seems to be the best alternative"
That being said, it grew on me as a general scripting language kind of generally in the same space as Perl.
https://en.wikipedia.org/wiki/AOLserver
https://en.wikipedia.org/wiki/StoryServer
So back in the early days of Apache and server modules, Tcl was a good option to build web applications. :)
- AOLServer (https://en.wikipedia.org/wiki/AOLserver)
- Rivet (https://tcl.apache.org/rivet/)
- Vignette (https://en.wikipedia.org/wiki/StoryServer)
- Safelayer (our own in-house implementation, the core team later founded OutSystems)