Why is Tcl syntax so weird (2013)
wiki.tcl-lang.org
wiki.tcl-lang.org
I just wish there was a Tcl that was redesigned from a modern perspective. Give me first-class lambdas. Give me unnamed objects that get destroyed automatically (with a callback) when out of scope[1] so I don’t have to use a weird namespace hack to make the object and rely on the caller to invoke the destroy method. Give me a stdlib that offers more functional stuff. Heck, give me async/await. And more too.
But even without all of that, Tcl is still a wonderful language and I often lament how it’s mostly died out.
[1] There’s at least one library I’ve used that actually does this, but AFAIK there’s no way to do this in pure Tcl so it must be a feature of the C API. Also I’m not sure if it actually tracks the object or just the variable it’s assigned to.
The modern version of Tcl will be great and a seamless integration with the OS shell will probably the killer niche application. Hopefully Oil Shell can modernize Tcl to some extent and incorporate the best features of Tcl with excellent OS shell integration capabilities.
[1] http://www.oilshell.org/release/latest/doc/oil-language-tour...
If you are looking into a modern version of Tcl, there is TIL [3]. It's a Tcl inspired new scripting language on top of D language. By having D language as the foundation it can perform all the features that you've requested including lambdas, async and then some more [4].
[1]https://news.ycombinator.com/item?id=28552998
[2]https://en.wikipedia.org/wiki/Cisco_NX-OS
But also, why can't I write modules in TIL? It's based on D, sure, but I shouldn't need to write and compile something in D just to be able to have some means of namespacing things. This very much feels like "I want to write most of my stuff in D but I just want to be able to whip up short scripts that for whatever reason I don't want to write in D".
And of course it seems to be ditching the pure simplicity of Tcl. It's like Tcl in that it's a command language and borrows syntax from Tcl, but it seems to be missing the fundamental concepts of Tcl.
[1] The author seems to hate the idea of people lining up equals signs in code or things like that. Ok sure, you can have a style preference. But that's what a code formatter is for, not an artificial and unprecedented level of whitespace significance.
The real question is: would they still be using it when given the choice?
For me, Tcl is a cancer that just doesn't want to die.
One way is to provide Python(python stdlib might be enough for simplicity) gradually, e.g. providing a Python binding for Tcl so for the future, you can write all new piece in Python, and it is either used directly or converted to Tcl behind-the-scene.
If a startup wants to displace an entrenched tool from Synopsys or Cadence, the underlying algorithms (millions of lines of C++ code) must be better. (And once that happens, they'll be acquired by one of these 2.)
On the front-end side though, areas like verification, debug, and various lint checks, I think there is more opportunity for smaller players to introduce point tools with better customizability & scripting interfaces.
Ultimately I think the industry is stuck in a local maximum, where the frictional costs of rethinking overall methodology, e.g. from SystemVerilog to Chisel, is too high to justify the change, even if the end result would be marginally (or greatly) better. (Not an endorsement of Chisel, just an example.)
Sometimes we've had to use it like an emergency super power to patch http applications on the wire.
The reason why some financial institutions are working right now is because of some iRules we wrote a couple for years ago.
If your company uses F5 boxes, you should befriend your F5 admins.
While Tcl may be a particularly good language for somethings, well over 90% of the teams I've found using it do so for legacy reasons, and they correlate very highly with poor SW engineers with even poorer SW practices. When I interview for jobs, I steer clear of any that lists Tcl. Not because of the language, but because it's a fairly useful signal about the quality of the team.
Even just making it easier to have lambdas reference variables from their creation scope while the creation scope is still on the stack would be an improvement. Today you can use [info level] and then construct a lambda body that uses [upvar #$level …] to reference variables from the original scope, but it's a PITA. Or you could cram the level into a temporary namespace variable to avoid having to manually construct a body string, but it's still a PITA.
Furthermore, if you process $ like that, this won't work for any other command that takes a variable name as an argument, and does something to it.
Isn't that by convention? Like there is a "upvar" to grab values of the prior stack.
if {$foo == 1} { puts $bar } else { puts $baz }
given that all the {}s are just non-expanded string literals, and what makes them be interpreted as code is the implementation of "if"? Sure, you can hardcode "if"; but the whole point of Tcl is that syntax constructs like that can be easily implemented as a library, which breaks if you have to special-case them in lambdas for them to work.Now if you used upvar, this kinda sorta works, but only so long as the lambda is immediately invoked by the function that it was passed to. If you want to pass it on, you'd have to wrap it in another lambda. And, of course, this only works for lambdas that don't escape.
I often lament how it has not died out. It's demise is long overdue...
I'm not sure that's an appropriate phrasing. The word "choice" implies that alternatives are available, and there a decision was part of the selection. I think "Has been used for the language that momentum has demanded" might be more accurate. ;)
lol what
The JVM is one target. You can also generate and run javascript code or create a native binary. But it will not be as smooth as e.g. python, so I can't really recommend that.
> Scala also seems to have something of a racism/white supremacy/misogyny problem.
I'm a member of that community for a long time and I really don't think so. I always thought the Scala community was a rather welcoming one. There certainly have been incidents in this community, just like they have been in other communities, but I don't think "Scala" has more of a problem here than any other language.
[0] https://core.tcl-lang.org/tcllib/doc/tcllib-1-19/embedded/ww...
However that experience lived on and gave birth to OutSystems.
If you take a look at jimtcl (minimalistic reimplementation of tcl, started by antirez - he of redis fame), it did take some steps towards the above.
- unified arrays with dicts
- proper lambdas
- (sort of) closures
In many ways, I personally feel its a shame that jimtcl has felt the need to tie itself down to tcl-compatibility as much as it has. A few more warts could have been fixed along the way.
Anyway, check it out. It's manpage is quite comprehensive
If Tcl had the other stuff, would it need upvar/uplevel or its funny braces and substitution rules? I'm no expert at Tcl but when I learnt it (mainly to use tkinter) I really had to rewire my brain to think about something as simple as _variables_ so differently
1. http://www.aolserver.org/ 2. http://www.carnageblender.com/
Versus the poorly conceived, poorly implemented, from scratch rush job based on a fundamental misunderstanding of Self.
In fact, we could have ended up with Self. Imagine that timeline.
Worst is better.
Have you ever had to debug code written by someone who implemented their own control flow operators? Not fun. I've seen it done with C macros. Don't do that.
From another way to look at it, nobody seems to bat an eye when using things like items.forEach() in, say, Node.js, even if this sort of thing is arguably much uglier to do in JavaScript vs. a "first class" functional language where common control flow operators are often just plain functions themselves.
There are many programming language concepts which may be innovative and beautiful, but whose popularity wanes because of practical flaws. (EIAS is another.)
Like any feature, it can be abused, but it can be very elegant.
Then you will like Lisp, Smalltalk and Forth!
What's weird about the Tcl syntax is that there is barely any. It's very dynamic so only the top-level of a file is parseable as a list of commands, anything else like a procedure depends on the implementation of the command which can be overridden at any time.
It's even used by built-in commands like expr and if which essentially implement a mini expression language which is different from Tcl.
Tangentially, I found that the primary author of SQLite and Fossil SCM, D Richard Hipp, was also a core team member of Tcl. The server side of Fossil uses a minimal dialect of Tcl and the build/test system is built with Tcl. [1]
[1]: https://fossil-scm.org/home/doc/trunk/www/fossil-v-git.wiki
Maybe it allows for some "clever" code or "powerful" concepts but for its use in that application, it was just not straightforward. It was used among a pretty large team and it just felt so messy and chaotic. At that scale I would want type checking and the ability to not have to think "okay is this a variable or is it getting interpolated in some other code, or what?"
LIL tries to be a minimalist but practical embeddable implementation, so it has basic optimizations like representing lists more efficiently internally. The price, of course, is code size, but also C API complexity.
Then why doesn’t it have macros? This is one of my biggest complaints with tcl, the other being that you have to escape newlines in forms. This makes much less pleasant then lisp.
For example if I have this Tcl code
[set foo [foofn bar [barfn baz [bazfn quz 1]]]]
I would love to write it like this
[set foo
[foofn bar
[barfn baz
[bazfn quz 1]]]]
But I can’t without escaping every newline (you better hope you didn’t forget one). If tcl had macros I could write it like this
[set foo
[thread-last
1
[bazfn quz]
[barfn baz]
[foofn bar]]
But instead I end up create a bunch of temporary variables so that my lines don’t get super long. It just feels less elegant then it could have been.Newlines only can work, but then the question revolves around implicit newline escapes (if there's an unclosed statement) versus a required escape and things can quickly get out of hand and readability if really long strings need to be passed around; like with nightmare long SQL queries or default / example config file blocks.
This works:
#!/usr/bin/tclsh
set foo [
lindex [
expr 2 * 3
] 0
]
puts $foo proc multiline {expr} {uplevel [regsub "\n" $expr " "]}
Use it as following: multiline {
set foo [
foofn bar [
barfn baz [
bazfn quz 1
]]]
}
try it in action: https://jdoodle.com/ia/jkaThe hardest part to understand when writing TCL "macros", is that it's all strings. You might be used to "inputs are s-expressions" from lisp, or "inputs are closure objects with pointers to code and local variables", but not in TCL. {} produces a string parameter. It is interpreted as an expression to be evaluated in parent context when passed to "uplevel". So "proc" takes 3 strings as arguments, and syntactically no different from "regexp".
There is a link to online playground, I encourage you to visit it and try various changes. No installation or signin required.
First off I think you want "regsub -all ...".
Second, since your regsub isn't really replacing newlines (except the first), the example isn't so good - your "set foo ..." works without the multiline proc because the opening square brackets are on the same line as the commands. So this also works: jdoodle.com/ia/jnc
Third, if you do change the example so that square brackets are on their own lines, as in the original request, then your version would work (with "regsub -all") but it might strip too much - like newlines inside nested quoting. See, for example: jdoodle.com/ia/jne
set foo [
foofn bar [
barfn baz [
bazfn quz 1
]
]
]Elegant!
join {{} \{ \}} {join {{} \{ \}} }
I think it tells a lot about the weirdness and awesomeness of the language at the same time.https://en.wikipedia.org/wiki/Eggdrop
https://www.tclarchive.org (Blast from the past!)
I was surprised to see that it is still under development.
After Eggdrop, it was Supybot that got really popular, although it is written in Python.
I still maintain a bot that began life as a mirc script, then a long time as an eggdrop bot, then ported to python based slackbot, and now most recently a python based discord bot.
Over the last 25 years it really has been a huge part of the way my group of friends interact. I recall the sheer wonder that I experienced when I learned about eggdrop bots and the huge amount that I learned while flailing around with tcl.
Same! It is quite interesting, I have not heard of it before.
My first experience with Tcl was through Eggdrop. I was really young at the time! I remember those mIRC scripts and different mIRC clients or something, they may have been through plugins? I don't recall, but I remember after installing them my mIRC looked very different and so on.
After Eggdrop came Supybot which was really popular at the time, then after that I just made my own. I have a Discord bot as well, I made it myself, although it is written in Lua because I made it around the time I was tinkering around with the language.
A more recent experience with Tcl was modifying Tclsh to make it suitable to be used as a replacement for bash. It works quite well now, I would say. Actually, a friend of mine did most of the job but still!
The CMake language was created in a haphazard way as well, with some other important problems that Tcl probably doesn't have.
Ironically, if I recall correctly, cmake came about from a Kitware medical imaging project that was heavily leaning on Tcl, yet when their build system needed a DSL they decided to hack something up from scratch :/
for {set sum 0; set counter 0} {$counter < 10}
{incr sum $counter; incr counter} {}
It's amusing how that pattern was adopted in Javascript (well, C/Java really I guess) as an optimisation. for (var sum = 0, counter = 0; counter < 10; sum = counter++) {}I had to code in it once, can't remember what, something trivial; but I had to learn Tcl. It was basically an obstacle to my work. I never needed to use it again, so I've forgotten it, so I wasted my time learning that language.
Could be worse. Could be Forth.
How so? Tcl has namespaces, a standard lib, runtime introspection, an OO system, threads, asynchronous programming capabilities via event loop, a GUI framework and is cross platform. Have you actually used it?
I wrote a semi-graphical general-purpose shell in Tcl/Tk for my own use - https://wiki.tcl-lang.org/page/gush . I used this as my main shell at work for 12 years, and only stopped because I retired last year.