153 comments

[ 7.4 ms ] story [ 196 ms ] thread
It's weird, I spent 3 years working on one of what must have been the largest TCL codebases in existence, since then I've reached for the language exactly zero times in personal or professional use. I have very little fondness for the language.
same. Back in ~2009 I had the pleasure/horror of debugging/fixing "TCL drivers" for a piece of Java software that aimed to integrate with various pieces of hardware. I'll never risk putting anyone else through a similar torture if I can help it. ...then again I've left a trail of Ruby/Rails behind me that might get the same job done :)
I think the comparison to bash etc is apt.

tcl is definitely much better, but equally uninspiring.

I think it is extremely cool as a toy language. I've loved learning it for fun. I absolutely never ever would want to have to use it to do something productive
What would you use instead?
For almost all the things I would use tcl for, I would instead pick whatever scripting language my team happens to be most comfortable with, with an eye on any larger company norms. In my various organizations, this has usually meant one of:

- python

- nodejs

- bash

Of those, I personally would prefer bash as the “organizer of commands,” but that’s probably not surprising from someone who would learn tcl for fun.

Usually, the use case for these things is some combination of gluing programs together or gluing programs to the specifics of their OS. In that regard you might think, that picking a language specific for the problem at hand would be wise. But pragmatically, I believe you want devs who are mostly focused on feature work in their own programs to nevertheless be able to “bring their head above the water” and still have immediate intuition about how to swim. So even though nodejs might suck for this, it’s also extremely approachable for somebody who spends all their days in js.

I am really drawn to the idea of doing all of this in something like nix, but I tried it and didn’t have time to get past the learning curve. And that points to the other issue:

You’re probably going to need to glue rpm scripts, Dockerfiles, specific system tools which have different amounts of portability, etc. At the end of the day, if there’s a “lingua franca” for the organization, it usually makes sense to use it so that nobody needs to spend any time becoming accustomed to the idioms of some unfamiliar language while they are simultaneously dealing with the unfamiliar terrain of dealing with other systems that they have very incomplete knowledge of.

If there’s no lingua franca, I default to bash as a larger lingua franca

In the 1990s the services in AOL were all written in C, using a very very good event based callback library, which had Tcl embedded in it. We had a very rigorous standard of nothing in the server was hard wired, any change that ops might want to make would be applied to a running server, and dev had the job to expose all configurable state as either Tcl Vars or Tcl commands. It was a no thread environment (one process per CPU and one CPU for the OS) so while your Tcl command was running you could do anything to the in memory structures you wanted as long as it was fast. The ability to have a Turing complete language available for ops to do config in was extremely useful, they wrote amazing Tcl making configuration on the fly.

Not sure any of it would have carried thru till today even if the business hadn’t stumbled, but it very productive in the 1990s.

This is a more interesting take to me than others since it seems you’ve actually learned it?

I see the response later that you’d rather use whatever the team already uses, but could you explain this very strong opinion?

I maintained a 200,000 loc TCL codebase running the front end for millions of lines of industrial C spread over hundreds of machines. It was glorious. After moving on, I’m still struggling to figure out why TCL is so unpopular outside that domain. Other comments seem to boil down to not understanding the language or how to apply it. So what’s your take?

That does sound glorious. And, to be clear, I am merely an amateur (lover of) rather than experienced practitioner. It’s also the only lisp-like I’ve learned, and it gets a fair amount of credit from me on those grounds alone. At any rate, the opinion is very strong because 1) the pragmatic angle that I’ve already mentioned, 2) the tooling hasn’t kept up, 3) the performance isn’t worth fighting for (although it’s really still fairly good), 4) the footguns are gloriously just around the corner.

I don’t know if all lisps suffer from that last one, and I don’t know about you, but there seems to be a clever solution hiding in every line. I think it would take discipline to have a codebase that remained cohesive and in a “single language”

For a company in the rental automobile space?
Because you work in semiconductor industry.
Is Tcl widely used in semiconductors because of a particular thing it does well or is it mostly because of inertia? I don't know a lot about the language so I'm curious :)
The language originated as a common language for semiconductor design tools.

Ousterhout saw that a number of design tools he was involved with all had ad hoc languages, so he developed Tcl as a single common solution to the 'scripting language problem'. This is partly why the language is designed to be as easily embeddable as it is.

Post this origin, Tcl developed a modicum of broader fame through Tk (one of the best/easiest early X11 toolkits) and expect (which is a tool for automating control of command line interactive tools).

I only came across TCL as the scripting language used internally by the F5 (BigIP) load balancer. Writing irules was fine because they are usually one and done. It was tempting to try to do complicated things until you realized that was exactly the wrong place to try to fix the underlying problems of a broken web application.
The best thing about TCL is it's not OCEAN.
Or have an ancient and undying passion for Eggdrop IRC bots. Eggdrop was an introduction to TCL for dozens of us.
I've actually found some use for it as a lisp-ish shell scripting language, when the project grows too large for a bash script. In cases where there's a lot of interaction with the OS and a lot of text processing that has to be done on the results, python just gets in the way and TCL is well suited for that.
Honestly I wish all the old awk fanatics had been tcl fanatics instead.
I found Tcl hard to write, read and debug. (But I'm quite impressed with some of Ousterhout's writing.)

In contrast, Python is easy to read, write and debug.

I quite like the small footprint of Lua as an embedded script language, which is easy to read, write and runs relatively fast.

I'd probably use Lua or a Scheme as an embedded scripting language if I had the need (generally, I try to not let my programs get so big that the require embedded scripting, but instead attempt to create orthogonal CLI commands that do one thing well and that can be scripted from the outside via POSIX sh).

Everyone likes lua but out of the box it's pretty poor for string manipulation, a particular strength of tcl. I don't consider them to have much overlap for that reason.

Lua's match system is cool for what it is, and how small its implementation is. But it's really not powerful in the end and lua has almost no other string tools in the standard lib.

lua has decent string lib in the stdlib, you can also use 3rd party libraries such as https://github.com/stein197/lua-string, I'm not familiar with tcl, can you elaborate why tcl is much better than lua in string manipulations?
In tcl strings are first class citizens as everything in tcl is a basically a string.
Lua has a very minimal string library that doesn't include basic things like escaping and interpolation. It doesn't include regex. I understand the choices behind these decisions and don't disagree with them. But what it means is now you're not just embedding lua, you're embedding lua, vendoring extensions to the standard library, and selecting a regex implementation compatible with your expected runtime and distribution method.

Tcl is built around string manipulation, it's the main and, for a long time, only data type. It has regex built in, a full set of string manipulation functions, and an interpolation primitive.

It's not about what's better. They are both full blown programming languages and you can implement any behavior you care to. In lua you have to care to implement string functions if you're going to do anything complex with strings. Tcl comes with them. That's all.

Although Lua patterns are quite elegant and, in my opinion, more readable than normal regex. Despite having a small string library, Lua still works for many use cases.
Not OP, but I think the reasoning behind that argument is: TCL has only one data type: string. Everything you do in TCL is reduced to string manipulations up to having optional function arguments starting with a - like a shell command. A string in TCL is like a list in Lisp, the most fundamental building block.

  #!/usr/bin/env tclsh
  
  puts $argv
I kinda wanted to stop reading after this example. It feels dishonest to start with an example for which there is a builtin. Why didn't you show instead how to output arguments joined by a comma or some other separator instead of space. If I were to update the Go or Python examples to use another separator, it'd be just a 1-2 character change, whereas for Tcl I have no idea how that would look.
The author is following examples given in a book, however.
Oh, I missed that. I guess it's alright then. I thought they chose this particular example to "showcase" Tcl by comparison.
Funnily neither version gives the correct result when you have arguments with spaces, e.g. for "-v 5" -d , the tcl one will print {-v 5} -d as a consequence of how tcl represents lists.
The author should have done:

     puts [join $argv]
to avoid that little issue. Doing "puts $argv" triggers Tcl's output of "lists" in a special format that allows the list to be parsed from the text again at a later time.
> Why didn't you show instead how to output arguments joined by a comma or some other separator instead of space.

The Tcl variant to output "comma" as separator (note -- this is not "CSV").

     puts [join $argv ,]
If you wanted "comma space" you'd do:

     puts [join $argv ", "]
If you actually wanted "CSV" then it would be (assuming tcllib is installed):

     package require csv
     puts [csv::join $argv]
I've managed to work on two TCL codebases in my career, one in 1992ish, and one in 2011ish. I was very surprised to be working on it the second time! I've said it before, but working on TCL is interesting, kinda fun, and ultimately a lesson in frustration once you get to a certain sized codebase. It really hammered home the need for static typing as your repo gets over 50k lines because it is so "type free". However, it is a cool thought experiment for it's premise, which is more-or-less, "what if everything is a string". It has a lot of benefits, and a lot of nasty side effects. I'm glad I spent time doing it, and I think the use case for which it was made ("Tool Control" roughly speaking) it has good ideas. TK was fun, as well, I miss it in some ways. But ultimately, I find TCL is a dead end for a programming language - the negatives accumulate too quickly.
You can have any type you want, as long as it's a string. :-) Don't forget about https://core.tcl-lang.org/expect/index. Comes in very handy sometimes.
Tcl hasn't been string based for over 20 years. It's time for this myth to die.
If it's a myth, the myth seems driven by the TCL team itself.

https://wiki.tcl-lang.org/page/everything+is+a+string

Yes, there is some detail about internal dual representation.

That wiki page has been around since before Tcl 8. Nobody says lisp is hampered because everything is an S-expr.
> That wiki page has been around since before Tcl 8

Maybe, but it's clearly been updated after Tcl 8. And while the page itself isn't calling it something that hampers tcl, it does cover that it's somewhat unusual, that is has implications, and so on.

Technically, all values are considered subtypes of strings, but the notion of types is quite different to those of many other languages. In particular, Tcl's types do not describe the memory storage model of their values. (They're implemented with 64-bit words and buffers and arrays and so on, but that's not what the value model describes.)

It works well as long as your goal isn't to totally eliminate boxing of values.

Tcl may not be strongly typed, but it is "stringly typed". :)
I never understand people's frustrations until I hear 50k loc base lol. That sounds hard in any language. I'd guess Tcl is pretty awesome if you keep things around 1000 loc or below (i.e. scripting).
In something like C# or Java with a good ide I imagine it's not too bad.

Interpreted languages like Python and JavaScript do suffer when code bases reach a certain size.

Even adding half-baked, not compile/runtime checked types such as "Python's Type annotations", "Python's Type Stubs", "Javascript @type-infused-jsdocs" and "Javascript with Typescript Declaration Files" manages to make those modern IDEs a lot smarter for things like checking if you're doing really obvious bad things until you go really ham into metaprogramming.
> That sounds hard in any language.

Yes, it is hard in many languages, having experienced it first hand. Just wanted to point out my experience with Elm (I know) 200k loc, I can refactor the codebase fearlessly, knowing that once it compiles it will "mostly" just work.

I fondly remember porting Elm 0.18 to 0.19, which was a big change in the language itself and the libs, me and my co-worker working across time zones almost 24/7 for over a week to make the damn thing compile, it was like struggling in the darkness, unable to see "anything" in the browser for like 7 days and when it finally compiled.. it mostly just worked!

It's sad that to see Elm getting so much negative publicity, but I do enjoy working every day on it.

Last I checked Elm was getting negative publicity not because of the language itself (heard a lot of good things about that) but because of the leadership?
Correct. Elm's publicity issues stem from how closed off the leadership is. There's Evan (creator) and a handful of trusted others that have a huge amount of sway over how the language and, arguably more importantly, the core libraries develop. They also get special access to write libraries that rely on native JS code (something you can't do as of 0.19 even locally in your own projects).

Elm is a great language and I've written extensively[1] about how nice it is to use in production. But if you want to get involved in the community, it feels like there's not much to get involved in. The fact that even on the Elm Discourse[2], posts auto-lock after 10 days means that the forum is now pretty dead compared to what it used to be in 2018-2019.

[1] https://charukiewi.cz/posts/elm/

[2] https://discourse.elm-lang.org/

I have the same feeling with Swift. I did a refactor recently w/o really thinking about it, just fixing (compilation) errors as they happened, and it just worked on first try.
I still work on a TCL codebase. I hate it. It makes heavy use of upvars, uplevels, and even a DSL written in TCL. It's so limiting. The interpreter only uses a single thread so better hope you don't need to do much computing with it. It's so hard to debug. Oh and be careful not to use brackets in your comments cos it interprets comments as if they're code...

The codebase is too big to rewrite but we're slowly untangling and hacking bits off to write in golang, but most of the business logic is in that DSL.

It's the exact same story with Python and Lisp. I love dynamically typed languages for fun little projects, but really don't like working with them on big must-not-fail type projects.
Tcl is a little gem of programming lore, an ugly duckling story where the ducklings are LISPs instead.

One of the most mind-blowing things to me as a (perpetual) Tcl noob is that when you look at

    proc my_function {x} {
        puts $x
    }
You are lead to believe it is an ordinary C-inspired language with an odd syntax. It took me an embarrassingly long amount of time to realize that

    proc my_other_function "x" "puts \$x"
Is equivalent to the former. Other little oddities like `upvar` are beautiful once you understand them. It has some warts but Tcl has never had the luxury of under the scrutiny that languages like Python or Ruby have had. This is one of the reasons I would really like to see a "modern" version of Tcl more suitable for programming in the large---something that happened to Python 3 almost as an accident, imho.
> a "modern" version of Tcl more suitable for programming in the large

Would lua fit that definition? Between game engines, redis, openresty (nginx w/ lua) and others I feel like it fits a similar need (adding code to existing applications).

I've done a fair amount of programming in Lua in the past but it still feels different from Tcl. Back in 2010 I would probably compare Lua to (a better) JavaScript due to its prototype-based nature. JavaScript evolved in a different direction afterwards.
The language itself is very different, but Lua is a replacement for Tcl in the sense that it's a fairly simple and small language that can easily be embedded. i.e. it's about use cases rather than the language design.
I understand what you mean, but this is not the point I was trying to get across with my original comment. Maybe that's the reason why I haven't touched this subject. Although both languages can be easily embedded, the programming experience is still different, and there are still lots of "freestanding" systems in both languages, so the language design comparison still applies.
The command-argument based workflow is so easy to grok as a model that it is intensely loveable. Generating arguments at runtime without messing up your substitutions can trip people up occasionally, but the straightforward nature of how the compiler understands the function is relatively wonderful IMO.
Well, there are classes and objects in there now. They're designed for modelling pretty heavyweight entities like widgets instead of lightweight things like linked lists.

It was a fun OO system to write. It's much more dynamic than it appears to be at first glance; it's first glance looks much like many other languages object systems with a few slight oddities (no new operator, but rather classes have a new method).

Most of the digital semiconductor design EDA / CAD tools from Cadence and Synopsys use Tcl as the built in scripting language. I have to work with thousands of lines of Tcl code whether I want to or not.

I learned Tcl / Tk back in 1995 because I wanted to write GUI programs and Hello World in Motif was about 2 pages of boiler plate code while in Tcl / Tk it was about 2 lines.

Then I started in the chip design world and Tcl took over so it was good that I already knew it. I was teaching the older engineers Tcl so it helped me gain their respect.

What are your thoughts? How do you like it as a language?
Although I never used Tcl myself, I've worked in/with teams that need to interface with these EDA tools, and most of the folks there are not SW programmers, but electronics folks who need to write Tcl to get their job done.

Their code sucked like crazy. Usually in such teams you are not evaluated by the quality of code.

Ever since then, any time I'm job hunting and I see a listing for a SW programmer that mentions Tcl, it's always been for EDA tools and I run in the other direction.

at my last job we used tcl for manufacturing tests automation. it was way better than the dsl they previously had. tcl was chosen because it was easy to port an interpreter to their c++ test automation framework
Maybe because EDA users think in terms of hardware description languages like Verilog. When I realized that they have to start with things as basic as clock edges and registering signals it dawned on me that that mindset also lends itself to TCL code unpalatable to SW engineers.
> Their code sucked like crazy. Usually in such teams you are not evaluated by the quality of code.

I worked in the semiconductor industry, specifically writing internal tools. I had to look at _many_ tools/scripts written in Tcl/SKILL/perl/awk/sed with some code being 30 years old and still being used.

Honestly, it wasn't the worse thing. There was usually very little abstraction, the code pretty much always told a story of what the writer was trying to achieve. Naming things was usually pretty bad and you'd get into some pretty gnarly regex/string matching, but at least it usually wasn't some over-complicated highly flexible but also restricting in-house framework.

Siemens NX uses it for the CAM post-processor customization.

    foreach line [split $file \n] {
            incr count($line)
        }

       foreach {line n} [array get count] { 
            if {$n > 1} {
                puts "$n\t$line"
            }
        }
......

IMHO that's hard to grok. count shows up in the middle of a loop and it's not clear to me what it is. Could be a function, an integer, a map, or an array.

Same problem with this:

>foreach {line n} [array get count]

Not really obvious what any of this does. Guessing it's taking a map, converting it to key/value array, and iterating.

> Could be a function, an integer, a map, or an array.

It is an array. 'incr' is a built in function that "increments" a variable by one.

Variable names followed by parenthesis () are Tcl arrays. So count(...) is "array syntax".

> Same problem with this:

> >foreach {line n} [array get count]

This is roughly equivalent to Python's "list comprehensions". "array get count" produces a list of values from the contents of the array named count (the list is "key1 value1 key2 value2 key3 value3 ..."

foreach is Tcl's "iterate over a list" function. In this case it is iterating two variables over the list at the same time taking two elements off the list each time. The first element is assigned to "line" the second element to "n".

> IMHO that's hard to grok.

Keep in mind that the default way C does for loops is the most un-intuitive way of doing a for loop. This Tcl example is less alien than the C for loop is for someone who has programmed in non-C like languages.

You learn it, and you get used to it.

    for dish, price := range menu {
        fmt.Println(dish, price)
    }

    for key, value in menu.items():
        print(key, ' is ', value)

    for (key, value) in hashmap {
        println!("{} {}", key, value);
    }
Really, it seems like that's a common syntax for languages with first-class dictionaries.
Those have an "in" keyword that makes it much more obvious what's going on. And none of them have the "count" variable that pops up in a loop but is somehow accessible outside it.
In python variables introduced in a loop are definitely accessible outside of it...
Every few years I use Tcl/Tk and the most common reasons are:

1- It's easy to make an executable for Windows (as well as running it on Linux);

2- It's easy to write a GUI.

Yeah, exactly what I used it for. I used to make small one off gui utilities for my team to use to save time doing certain tasks.
Yep, what I've always appreciated most about Tcl is ease of using Tk.

Worst way to make a scripted GUI: dtksh

And there's nothing special about Tcl the language that makes it special for scripting GUIs -- some people just put in the work to make a cross-platform GUI library and now everyone using Tcl benefits from it. I really wish Go had something similar to Tcl/Tk. I know making a cross-platform GUI library is hard, so how did Tcl/Tk's authors do it? All the way back in 1991, which still works even today?
Its easy to develop, surely, but my style feeling hurts how ugly TCL GUI looks like compared to modern GUIs
Given the recent trends in "UX" I would regard that as a a feature though.
One thing about scripting languages is that it doesn't seem like a hugely meaningful choice anymore.

GPT-4 can easily generate trivial scripts in any language.

Any complex codebase can be maintained in a typical language.

So curious as to why this got downvoted -- it feels exactly right.
Any sufficiently complex LLM-generated program is (semantically) indistinguishable from garbage.
I've found that GPT4 is particularly good at generating TCL code. Possibly because what's out there is generally high-quality, possibly because there's very little syntax for it to keep track of.
Well duh, that's not what you use it for. You use it to generate parts and snippets quicker.
GPT-4 is fantastic as one-off scripts for any task.

It can produce scripts in seconds that might have taken technical support people an entire day (stretched to a week or more of work) prior.

Of course, it can't maintain a codebase like a professional developer can. Thank God.

Tech type people that previously found a massive value in producing simple scripts probably wouldn't like this. It erases the value of the skills they developed.

Only a professional programmer is insulated from this obsolescence.

I am sympathetic to the fact that low-knowledge tech workers had their value erased over night. I don't have any solutions for this problem.

The Python and Tcl programs don't do the same thing. The Python output is in most-common order, which requires a sort. The Tcl one is in arbitrary order.

The idiomatic Python matching what the Tcl code does is:

    #!/usr/bin/env python

    import collections
    import sys

    for p in sys.argv[1:]:
        try:
            with open(p) as f:
                c = collections.Counter(f)
                for k, v in c.items():
                    if v > 1:
                        k = k.rstrip("\n")
                        print(f"{v}\t{k}")
        except Exception as e:
            print(f"dup: {e}")
            continue
Except, even then there are three differences:

1) the Tcl code accumulates the counts across all the files, the Python code resets each time. Though the Tcl code reports the counts after each file???

2) the Tcl code has a file descriptor leak (one of the big issues I have with Tcl is in dealing with resource management. I've used an upvar with a delete trace to emulate local scope, but that makes passing the result upstream tricky).

3) the Tcl code includes the empty string "" after the final newline in the count, which doesn't make sense.

To show the issue, I've replace the Tcl code so it outputs quotes around the line:

                puts "$n\t'$line'"
and set the file descriptor limit to 10 before having it read a file containing only two lines, each containing "A":

  % printf "A\nA\n" > x
  % limit descriptors 10
  % tclsh dup.tclsh x x x x x x x x x x x
  2 'A'
  2 ''
  4 'A'
  3 ''
  6 'A'
  4 ''
  8 'A'
  5 ''
  10 'A'
  dup: couldn't open "x": too many open files
  dup: couldn't open "x": too many open files
  dup: couldn't open "x": too many open files
  dup: couldn't open "x": too many open files
  dup: couldn't open "x": too many open files
  dup: couldn't open "x": too many open files
  % python dup.py x x x x x x x x x x x
  2 A
  2 A
  2 A
  2 A
  2 A
  2 A
  2 A
  2 A
  2 A
  2 A
  2 A
Because you are forced to. That's the only reason.

Otherwise please use something modern and sane like Deno, Python, Go or even Rust.

TCL has many large flaws that those languages don't share:

* No static typing so trivial errors are not caught early and code is difficult to understand and navigate.

* Everything is a string (TCL people try to claim otherwise but semantically it really is true). This leads to typing mistakes too.

* Quoting is a mess. It's simple in that the implementation is simple, but languages shouldn't optimise for that alone. Actually getting quoting right in TCL is ... well it's not as bad as Bash or even YAML but it's still something you have to think about, which isn't true for any of the other languages I listed.

If you need a language to embed in your program then while I'm no Lua fan, it is at least significantly better than TCL.

Almost all quoting for non-trivial cases comes down to the [list] command. It does the Right Thing, especially in the critical cases where you're generating a command to call later. Pretty much everything else is either much simpler to the point of needing no thought at all, or complex enough that you're best off writing a command to do it properly (e.g., because you're generating JSON or CSV or some other language like that) as you'll want to test it thoroughly too.

It's hard to be much more specific than that without talking detailed examples.

My biggest question about TCL--pronouncing it: T C L (each letter pronounced on its own) or tickle. I've heard it pronounced both ways by different programmers
TCL is a primary language for sqlite testing: https://www.sqlite.org/testing.html

I never liked TCL because the string quoting rules were almost as bad as Shell's. For small scripting I prefer Lua.

The only two times I've touched something remotely tcl was - working on Metal Gear Solid's port from PS1 to PC - it used TCL-like scripting language for the levels, functions were main-like, e.g. "Chara_Init(int argc, const argv[], / something else here */)", and then it was quickly parsing arguments (like tcl) to initialize initial state and types of characters/items/etc.

The second one was through Maya, if you can call maya's language tcl.

It was fascinating to me back then, but nowadays I'm leaning more and more towards static typing.

This is an amazing - I remember that PC port and you can even buy it on GOG today.

Do you have any interesting stories from the porting process?

This brings back memories. I used TCL/Expect for automating 3rd party software we were told could not be done. TCL/Expect: Hold my beer!

  > Ousterhout's dichotomy claims that there are two general categories of programming languages:
  > 
  > low-level, statically-typed systems languages
  > high-level, dynamic scripting languages
I understand that this may have seemed somewhat more true at the time it was originally stated, but it's not really been true since the '90s, and it's certainly not true now. What an odd thing to lean into in this day and age.
Are you saying the lines are blurred, or that there are more tiers of abstraction?
It's all shades of grey. Look at C#, it's a statically-typed high-level language which runs in a VM, but can also be compiled to native code. It has a massive standard library and can do all sorts of script-y things (see eg, top-level statements), but can also be tightly optimized to avoid GC allocations. You can mess with pointers in unsafe blocks.

The only thing it really can't do is kernel code.

Even C++ is incorporating more and more high-level constructs.

The general principal of alternating soft and hard layers is still a useful design tool. Even starting from silicon with the microcode emulation of the x86 instruction sets, kernel, syscall interface, building an app and exposing configuration, whether into Tcl, yaml, tool, .properties, json or xml, it’s very likely the consumers of complex software will want to configure its characteristics into a specific use case, but the implementation will be more general. Look at LLM as he ultimate soft layer.

Unless your team manages to never write YAML files.

The author should rather be honest and say "I like TCL just because", instead of coming up with contrived examples to state alternatives are bad.

E.G, in the Counter snippet, why make some complicated code when Python is designed to make it simple?

    import sys, collections

    for p in sys.argv[1:]:
        try:
            with open(p) as f:
                for k, v in collections.Counter(f).items():
                    if v > 1:
                        print(v, "\t", k, end="")
        except Exception as e:
            print("dup error: ", e)
I don't buy the argument of simplicity here. Also, if you are going to just do "get", you don't need requests, the stdlib is fine.

And I don't get the speed argument either, given his script uses most_common(), that basically sorts the entire dict, which none of the other codes do. Yes Python is likely slower, but let's not push it.

Also the Go code is more complicated, but you can cross compile it and ship it as is. And it's fast.

I get it, TCL is cute, but making up arguments is not selling it.

TXR Lisp:

  (each ((file *args*))
    (catch
      (dohash (k v [group-reduce (hash) identity (op succ @1)
                                 (file-get-lines file)
                                 0])
        (put-line `@v\t@k`))
      (error (e)
        (put-line e *stderr*))))
The "take command-line input and print it out" in Python is even more succinctly written:

  import sys
  print(*sys.argv[1:])
The author, while having a passing familiarity with it obviously, is clearly not a Python expert, so take all the Python stuff with a major grain of salt. Like they claim not to know how to get granular exceptions out of the requests modules:

>The requests here is a third-party package that required installation and a virtual environment to use. I don't know how to catch more granular exceptions in this example.

so I guess they even didn't RTFM:

https://requests.readthedocs.io/en/latest/api/#exceptions

Yeah—as a TCL fan, I agree. Comparing implementations of common coding tasks with other languages doesn’t highlight TCL’s strengths or, really, its purpose.

Personally, TCL fits a niche like QBASIC did. QBASIC was the shortest path from brain -> code drawing on a monitor. Literally 1 line to draw a shape, no initialization and not even an entry point function.

TCL similarly lets you just get on with what you’re doing when you need glue code, GUI’s, and DSL’s. It is easily (even trivially) able to do things that are just a pain in other languages, especially all at once:

- interop with native code (no limits on who calls who or in what order)

- define GUI’s that behave well without it being a huge pain to make anything non-trivial (lookin at you, UE5)

- create novel control flow that feels built-in

- implement an interactive GUI debugger with breakpoints & variable watch in ~200 LOC (saw this once, it’s amazing what you get “for free”)

- save or load a running program’s entire state, including code defined at runtime

- detour any function, allowing you to optimize or patch on the fly

- run from tiny, standalone executables so your users don’t have to install a ton of crap just to run your widget

There’s more but you get the idea. It’s been around for decades for a reason :)

That's actually a much better sale pitch than the article.
Reminder that TCL was programmed at a time when SPARCstation IPXes with a maximum of 96MB RAM were being used.

Some of the lower-end SPARC machines could only have 16 or 32MB RAM and had perhaps 10 to 12 MIPS of computing power.

Expect, which became a very important extension of TCL, was released in 1990, when the SPARCstation 1+ with about 15 MIPS and max RAM of 128MB was introduced.

Thus any extension language like TCL had to be small and efficient; especially when you consider it was designed to be embedded inside another program.

As someone is pointing above Tcl is nowadays used as the shell language for many EDA tools for which it is normal to consume multiple TBs of RAM.
Sure its good but its a one off script, so who really cares how fast the startup is? Or how elegant it is? I can literally ask LLMs to write a rough working code in seconds and I only need to fix it up a little bit. There's way more resources to find solutions in Python out in the wild that I can leverage.

I would imagine if you just have a tiny bit harder problems, the Tcl code quickly becomes unwieldy and you end up digging through the archives to find some wizard's tome (or maybe there's a large community of Tcl users out there? IDK).

I can easily spin up a GUI in an hour tinkering with PyQt. Can you do the same in Tcl?

DSLs like this tend to have a very nice local maxima. But once you stray away from its original use case you start writing some really confusing code.

"I can easily spin up a GUI in an hour tinkering with PyQt. Can you do the same in Tcl?"

No, it would probably take 10 minutes with Tcl/Tk ;-)

The author should investigate their networking setup. I can run their Go fetchall example in no more than 70ms. Their benchmarks are surely dominated by noise.
No Perl comparisons? I must be a dinosaur, but Perl is the best for reading in text, regex matching/search/replace/, and outputting a transmorgified result.
Came here to say this. Probably the comparison with Perl is the only one that matters in this context.
my espresso machine has software written in TCL and within the group of owners/hackers it's quite the bit of drama how much everybody regrets the original developers choice for it and his insistence it is still a good choice. personally, i value language aesthetics highly and TCL is an ugly one.
Decent proved that they can't do a good job at software and don't really have a vision or intention to do well. The owner's proposed "fix" for TCL is a rewrite using "vanilla javascript" using little or no libraries. What?
i just don't get it, considering they are basically completely relying on unpaid labor from the community to get even the TCL app front end working. the defaults are terrible and life became so much better after the mimoja-cafe frontend came out.
Yeah, and most of the maintainers have largely quit now because of abuse from John Buckman. I think Mimoja contributes occasionally but not in a large capacity.