The Tcl War (1994)
vanderburg.org
vanderburg.org
Around 2003 I was getting very heavily into what we used to call "Dynamic HTML", which of course required programming in JavaScript. At the time JavaScript was looked down upon by most professional programmers as a toy. A toy that had buggy implementations in various browsers, that lacked the strict typing of C++ or Java, that didn't have classical inheritance, that had no good IDE, and, worst of all, that you could create some terribly confusing bugs with.
At the time I'd moved to Fort Worth which let me attend the monthly Pragmatic Programmers meetings/dinners at Spring Creek Barbeque in Addison, TX. This was a meeting with a lot of polyglot programmers and "old timers", and there was a prevailing attitude that programming languages were just tools, and a good programmer learned to use many tools well.
Anyway, there I was one night ranting about JavaScript to someone I only remember as Chris. I probably chewed his ear off for a long time about how terrible JavaScript was. After what I'm sure was many minutes, I paused to let Chris tell me how much he agreed that JavaScript was terrible. Instead, he simply said: "You need to learn about prototypical inheritance."
This caught me off guard. I don't remember if it shut me up, but I hope it did.
Fortunately I actually took Chris' advice. While I'd understood that JavaScript had prototypical inheritance, I'd never really taken the time to understand how it really worked. I'd also never really grokked how scopes worked. As I properly learned these features, I started to gain a new respect for the power of the language, and it quickly became my favorite.
So, now when I have a strong negative reaction to a new language or tool, I ask myself if I'm reacting because of a fault in the language or if I just don't like that feeling of being less productive because I haven't learned the language yet. Usually it's the latter, which means I need to grit my teeth and bend my brain and learn.
(P.S. Chris, if you're reading this: Thank you! I owe you a millions lines of code in grattitude!)
I could have sworn it was a _different_ Chris. I remember someone with black hair. He may not have frequented the meeting as much, because I don't remember seeing him again after that.
(P.S. I've updated my profile.)
This is how I still view JavaScript.
I presume that by "look up in which order..." refers to lsearch vs "string first". Yup. Annoying; one's "needle haystack" the other is other way 'round. This being said, I am skeptical that this grinds anyone down. It'd have to be one grain of sand on a piece sandpaper.
My experience with Tcl is mainly that if I have to extend or modify a script, some care must be taken to design the thing for that upfront.
But after a couple decades watching comp.lang.tcl, I think the big leap is that you either embrace the event driven model or it's not nearly as much fun.
That matches my experience with assembly language.
Even in C, I can just begin coding and a good design emerges from prototype code. Months later I understand everything, and have a good time maintaining it.
[0] Show me your code and conceal your data structures, and I shall continue to be mystified. Show me your data structures, and I won't usually need your code; it'll be obvious. -Eric S. Raymond, The Cathedral and the Bazaar
What I've found is that most languages have language smells that you just have to get used to. The same is true of every language you listed there. Using 'upvar' and the like quickly becomes second nature and barely poses a problem in Tcl code.
Given what else you can put into this category, it's not very meaningful.
I agree wholeheartedly with the last paragraph of Mr. Ousterhout's reply here - and I must say, a smart, classy and almost Tcl-ish way of a jab at its distractors:
http://vanderburg.org/old_pages/Tcl/war/0009.html
I came across Tcl/Tk while doing Motif in a large C-based project. I simply couldn't believe how powerful, simple and succint Tk was compared to Motif (or anything else since). And it ran on Windows, Unix, Linux and Mac OS, to boot. It was too late for that project to switch, but all my other projects have used Tk if they ever needed a UI.
Similarly with Tcl. I still think the best introduction is Mr. Ousterhout's original Tcl/Tk book. It stands as one of the best language books on my shelf. Combined with Tk, one can put together a working application prototype in no time.
Of course, this was eons ago. Nowadays, Tcl offers one of the best environments with a complete set of packages ranging from web servers to image and sound processing. Plus, you can distirbute your program and all of its media and support files easily as well.
I believe Tcl has been mischaracterized and has suffered in terms of open popularity. But for insiders, it remains as one of those secret indispensable Ninja tools that is used over and over again for competitive advantage.
When it comes to an "AI" language vs. typical language with an "AI" library, I will just repeat a phrase that is often used in the field: what you thinnk of as an AI problem today will no longer be considered AI tomorrow, since it will then be well-understood and implemented in many places. People used to say that in response to the (seeming lack of) progress AI had made to date. A good example of that is Siri or Amazon Echo. Not many people consider it an AI problem anymore, or so it seems.
An interesting discussion here: [2]
[1] http://lambda-the-ultimate.org/node/3891#comment-58302
[2] https://web.archive.org/web/20110102015130/http://basiscraft...
I'm guessing you mean it's the second possibility, but I can't figure out how you get to there from reading it.
The second is writing style. The Tcl War post is classic RMS. Compare it to this reminiscence from Lord and it's hard to imagine they were written by the same person.
In short, I retract my claim. Sorry to whoever I misled! My confidence was completely misplaced.
I can't find anything archived to check but, as I recall, Lord later posted a bizarre sort of semi-retraction in rms' name, and rms fired him soon afterwards, possibly as a result. Perhaps that's partly a source of rms-didn't-write-it ideas? I don't remember the suggestion at the time.
The Tcl language OTOH .. awful once you tried to do anything mildly complicated.
array set FSM {
init {
...
set state two
}
two { ...
}
}...
set state init
...
eval $FSM($state)
I have just put together too many things that would have been severely daunting in any other way in this manner to agree with you.
Beyond that, Tcl comes with a rather complete runtime, and using tclkit, you can very easily create standalone and small (<2M) installation-free packages out of your program. This is very valuable, especially if you have to distribute to Windows. This is where Tcl easily pulls ahead of a lot of languages.
And often I use Tk for the user interface of my Lisp programs via Ltk, which brings both together.
Thanks to amelius for the "Tcl the Misunderstood" link. I agree with that, for the most part. I haven't written Tcl in many years, but I don't think it deserves the reputation that it has.
Goes without saying that there's a nub of truth in those ancient rants. Tcl can be kind of hard to catch on to, but then again, the Gnu "replacement", the Guile implementation of Scheme, is also hardly a mainstream favorite. Plenty of hate is expressed toward Lisp-derived fully parenthesized languages, Scheme included.
The not-so-dirty secret in the "language war" is that Tcl is itself very much a Lisp-like language, and over the years has increasingly adopted many features that make it even closer to languages like Scheme.
Having become reasonably fluent in both Tcl and Scheme I see similarities that outweigh syntactic differences. Not identical of course, but translating programs across them is fairly straightforward compared to C-like code, e.g., Javascript.
Maybe Lisp derivatives are an acquired taste, or maybe there some inborn twisted brain thing that entices some and repels others. At any rate, I'm convinced Tcl and Scheme are very capable languages, admittedly different in approach vs. more commonly used systems. Looking back it is ever so obvious that the old war was fought between two sects of the same tribe, and isn't that often the source of the fiercest rivalries.
"In 1993, the only real contender was Tcl, which had been explicitly designed to be embedded into applications. However, Tcl had unfamiliar syntax, did not offer good support for data description, and ran only on Unix platforms. We did not consider LISP or Scheme because of their unfriendly syntax. Python was still in its infancy. In the free, do-it-yourself atmosphere that then reigned in Tecgraf, it was quite natural that we should try to develop our own scripting language ... Because many potential users of the language were not professional programmers, the language should avoid cryptic syntax and semantics. The implementation of the new language should be highly portable, because Tecgraf's clients had a very diverse collection of computer platforms. Finally, since we expected that other Tecgraf products would also need to embed a scripting language, the new language should follow the example of SOL and be provided as a library with a C API."
I have an enormous amount of respect for the FSF. But it has been most effective when it has working code, like gcc or emacs. The political pronouncements not backed up by working code were actively harmful.
Oh ah, and there's Guix[1].
[0]: http://wingolog.org/
Thats why a plucky student from Finland managed to steal their thunder by getting a monolithic kernel out there while the FSF was trying to get that microkernel working for the Nth time.
And then you never stop bike-shedding.
(Submitted page looks like an Usenet Who's Who index ;-)
"I didn't design Tcl for building huge programs with 10's or 100's of thousands of lines of Tcl, and I've been pretty surprised that people have used it for huge programs."
lots of Tcl criticism stems from the fact that people started using Tcl not in the way it was intended.
It has features like namespaces and package management since at least 8.x . Language comparison is always challenging. I've had less trouble with Tcl than with just about any other language. But it rather requires thinking about the problem in certain ways. The main thing it requires is adherence to an event driven model.
https://www.fossil-scm.org/xfer/doc/trunk/www/th1.md
It's a tiny Tcl subset, implemented in only a few kloc. It's used by Fossil as a HTML templating engine but it's easily adaptable for other things. It's small enough to be understood and does an excellent job of demonstrating the core principles of how string-processing languages think.
ps: th.c is one fun name I failed to anticipate.
Tiny Tcl implementations are fun in general and perhaps easier to produce than tiny Scheme implementations — as long as you are willing to concede that everything really is a string. :-) (I.e., no caching binary representations; you have to parse from scratch each time.) In a similar vein as TH1 but with a little more functionality there are Picol (https://tcl.wiki/Picol) and LIL (http://runtimeterror.com/tech/lil/).
Disclosure: I maintain an expanded fork of Picol. The original version of it written by antirez was only ~550 LOC but with suchenwi's additions and mine it is now around 3100. There is a link to it on the wiki page. The change that I am most fond of is making it an stb-style (https://github.com/nothings/stb/) header library.
Oh, I agree with you on that. My point was that Tcl makes it especially easy to "cheat" and avoid building an AST. You may do this when you only care about writing an interpreter in few LOC, like the original version of Picol, quickly.
A Tcl interpreter in VHDL sounds interesting. Do you have a public repository for it?
drh is a former Tcl Core Team member[0], and probably most famous as the author of Sqlite, originally a Tcl extension that "escaped into the wild"[1]. Sqlite also has a comprehensive test-suite written in Tcl[2].
[edit: footnotes]
* nuclear power plant operations
* high-performance visualization and analysis of microscopic images.
* design analysis of high-resolution camera light sensors.
* embedded programming of Cortex-M3 ARM v7-Microcontroller.
* satellite control systems.
* multi-platform/compiler automated C++ library compilation.
* customization of the Fossil VCS.
* scripting and visual programming on Android.
* communicating sequential process programming.
* Linux D-Bus scripting.
Slag Tcl all you want, but it's still being used every day by brilliant programmers to ship real products, in environments where reliability is crucial. How does Guile stack up to that? Or any other unfashionable programming language for that matter?
Maybe more effort should be put into understanding what these programmers see in Tcl that the critics can't.
In any case, a lot of good points are raised by both sides. As an Emacs user, I appreciate Stallman's points, but he does make a fatal mistake, in that he doesn't include popular extensions like itcl in his evaluation. That's like evaluating lisp without considering popular macros, or the potential of macros. While that doesn't alleviate the problems Stallman has with tcl's lack of datastructures, those are not insurmountable with a couple of well-written C-extensions, assuming that tcl's C interop is any good at all.
Also, tcl is a pretty terrible lisp, as although they have a lot on common, the differences are substantial enough for fans of one to have some degree of distaste for the other.
The most entertaining part is that Stallman criticises tcl for lacking common datastructures, being slow, and having bizarre syntax that appeals to hackers alone. ESR (and, I believe, Stallman, although I am unsure), goes on to note the common use of dynamic scope, confusing quoting mechanism, and the horrors of upvar and upvalue.
Gee. DOES THAT. SOUND. FAMILIAR?
If it does, it's because most of those problems also appeared in MacLisp, the direct predecessor to Common Lisp. Many of them also appear in other lisps:
Linked lists, an unusual datastructure, are one of the few well supported by Lisp. Lisp used to be quite slow, and many implementations still are. Dynamic scope is still the default in elisp, and macros just barely hold the system together when you're writing lots of code, a cicumstance that Stallman claims elisp is actually better in than tcl. As for confusing quoting, `(there ,(is 'quite) ,@(a lot) of that in lisp). And upvar and upvalue are in some ways less dangerous than macros.
Actually, lisp used to have its own version of upvar and upvalue, coupled with a mechanism called the fexpr that let you get rid of a lot of the quotes. These were not implemented in most later lisps, due to the fact that they are nearly impossible to optimize well.
At the end of the day, whether you love or hate tcl and lisp, there are people out there that are stuck using far worse extension languages. Like these poor sods: https://gitlab.com/xonotic/xonotic/wikis/QuakeC/Introduction....
Excellent. I thought of googling for relevant keywords to check if the article was online (after posting my previous comment here), but you saved me the trouble. Thanks!
Did I miss the rebuttal to this?
The other two things are totally valid. Tcl has no references, so you can't build your own linked list. And all values are (at least semantically) strings, so numeric operations are slow.
But of course, a lot can be done to optimize those things in the implementation, and over time at least some of that optimization was done.
I've had cases where opening a 'C' program as a pipe and doing heavy number crunching in the 'C' program outperformed native Tcl.
That all seems normal to us now, but it was uncommon back then.
Was that the case in 1994, or are you writing about the current state of Tcl?
I didn't get to it until around v7.x around 1995 and lists feature prominently in Osterhout's book.
All values are _still_ semantically strings (it's a core tenet of Tcl: "Everything is a string (EIAS)"), and in 1994, they were practically strings, too (that was the implementation). In 1999 w/ Tcl 8.0, Tcl became byte-compiled and adopted "Tcl_Obj" to represent values[0]. The Tcl_Obj (nothing to do w/ object-oriented programming), is what's called a "dual ported" object. It contains a string-representation of it's value (to preserve EIAS), and a "native" value of it's last computed use. For example, if you:
% set a 9.0
% expr { $a * 0.01 }
The native value of the Tcl_Obj $a refers to will be a float. Repeated calls to $a in a float-context will continue to use this already-computed native value. No need for further string interpolation.[0] http://www.tcl.tk/software/tcltk/8.0.tml
[edit: formatting]
University coders and their obsession of purity of syntax (map/purity) superior to actually dealing with the true problem of the hardware is looking (territory/practicality) is looking for me like an Aristolecian argument of superiority of the style over the «getting things done».
Well, as spotted in the answers, expect is a nice non university bred innovation (is it?) that is still a de facto standard in handling interactive session (stateful) with a simple syntax that helps getting things done with maintainable code.
It is ported in Perl, python ... and I think this is probably a point for what Tcl is worthy : getting things done.
Practicality beats purity.
And as of today it is still the most portable way to write embeddable graphical user interface that have good FFI.
RMS is of course a bit nuts, and perhaps living in some kind of ivory tower, but it's not the academic ivory tower.
Perhaps I also have a European bias here. After the war, the Americans got to play with their computers early on, and their academics ended up with Lisp. The European computer scientists had to wait, and thus had nothing better to do but think. They ended up with types and ML (the family that Haskell sprang from).
These days, it seems that the European tradition has firmly won in the most academic parts of computer science. Lisps are still around, and with Clojure have seen more mainstream success that ever before. But in Academia the only Lispers left standing seem to be the Schemers, and they have warmed up to static types, too. (They did some great work on contracts.)
Just for saying I did not invent the lisp/scheme obsession directly from his web page[1] :
The most powerful programming language is Lisp. If you don't know Lisp (or its variant, Scheme), you don't know what it means for a programming language to be powerful and elegant. Once you learn Lisp, you will see what is lacking in most other languages.
When I learned Haskell afterwards, it was the opposite: I thought I'd miss S-Expressions, but I learned to like its more baroque syntax.
S-Expressions have the chief virtue of making even the most crude macro look no different from the most over-engineered builtin to the language from the user's point of view.
And they clearly separate the syntactical space in the language, so that new features (whether as macro or built-in) can always find a space. Compare to the cracks of C they had to fit C++ into.
Haskell might be even worse. The chief obstacle to adding OCaml or-patterns to Haskell (https://stackoverflow.com/questions/24700762/or-patterns-in-...) seem to be finding a syntax that's both pleasant and fits between the strands of the fine web in ascii space of already valid Haskell programs.
I usually give types for my top level functions. It's good documentation, and also prevents most of these kind of issues. (For a similar example, human mistakes with operator precedence usually lead to compile-time type errors in Haskell, seldom to runtime problems like in C or C++.)
I am aware that the information exists somewhere, and I think I got a link a bit back, so I'll have to go track that down. But it is absolutely baffling that people don't discuss it more. Would you be able to write Python if nobody told you about the indentation rules? Of course not.
I'll have to find that link...
I wrote plenty of Haskell commercially (and for fun). Not once did we run into that problem.
Or in other words, being a "glue" language?
(define (my-reader)
(let ((c (read-char)))
(when (not (eof-object? c))
(display c) (newline)
(my-reader))))
(with-input-from-file "myfile" my-reader)This part of his proclamation anticipates and softens the ironic impact of subsequently promoting a Scheme, further mitigated by in the same breath promising the availability of a parallel notation that will provide the blub syntax for non-hackers.
(Of course, he was right about a dual syntax approach being viable: today we have virtual machine environments with multiple languages. As a Lisp hacker, Stallman knew about the existing history of such practice, like CGOL for Common Lisp and whatnot.)
In the physical world, we change the territory (e.g. alter the landscape, build). That's what is analogous to coding.
It is helpful for the territory and all of its manipulations to be clean and well-organized.
This is not just an "obsession" of "university coders".
And if you like TCL's command syntax, srfi-49[0], srfi-110[1], and srfi-119[2] all push scheme towards that to varying degrees.
0:http://srfi.schemers.org/srfi-49/srfi-49.html