[HN Gopher] Why is Tcl syntax so weird (2013) ___________________________________________________________________ Why is Tcl syntax so weird (2013) Author : blacksqr Score : 76 points Date : 2021-11-07 20:44 UTC (1 days ago) (HTM) web link (wiki.tcl-lang.org) (TXT) w3m dump (wiki.tcl-lang.org) | AnonC wrote: | I've seen Tcl used to write testing systems a long time ago, but | never really worked with it. | | 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 | [deleted] | tracnar wrote: | The Tcl wiki is quite strange, it has interesting content but | most pages are discussions like this one and it's hard to find | what's relevant or even correct. | | 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. | rodgerd wrote: | It's an accessible Lisp with square brackets. | int_19h wrote: | Not really. References are pretty fundamental to Lisp, but | are (at best) bolted on in Tcl. | natrys wrote: | I have been writing some Tcl for the last couple of years, | mostly in place of shell scripts. Going to Tcl wiki is always a | surreal experience. I think this old comment captured it | perfectly: | | https://news.ycombinator.com/item?id=9098859 | blacksqr wrote: | Equal time: | | https://news.ycombinator.com/item?id=9102916 | kevin_thibedeau wrote: | That's what wikis originally were. Wikipedia's curated ontology | is an exception that only looks like the rule because most OG | wikis have died off. | emodendroket wrote: | Emacswiki is one active one still like that and the effort to | replace it with MediaWiki was ultimately abortive. C2 is also | big but I think mostly dead. | lilyball wrote: | I've always loved Tcl because of its absolute purity and | simplicity at the language level. I love how you can implement | your own control flow operators that look like built-in ones. I | love how easily you can make DSLs. | | 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. | CornCobs wrote: | I believe a lot of what makes Tcl the way it is is precisely | because it does things different from most other languages with | regards to closures, lambdas, scoping etc. | | 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 | valenterry wrote: | Checkout Scala. It allows you to do pretty much the same, i.e. | the syntax is so flexible that you can even make 'puts "Hello | World!"' work and implement your own "if" that looks like the | builtin one. It also has first-class lambdas and the other | stuff that you asked for, but obviously there are also | differences. | lilyball wrote: | Scala runs on the JVM, which makes it not at all suited for | scripting. Scala also seems to have something of a | racism/white supremacy/misogyny problem. | valenterry wrote: | > Scala runs on the JVM, which makes it not at all suited | for scripting | | 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. | mrbukkake wrote: | >Scala also seems to have something of a racism/white | supremacy/misogyny problem. | | lol what | tverbeure wrote: | Tcl has been used for decades as the language of choice in the | electronic design automation world. | | I often lament how it has _not_ died out. It 's demise is long | overdue... | nomel wrote: | > as the language of choice | | 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. ;) | pjmlp wrote: | I love the language as well, we did lots of cool stuff with Tcl | in 1998 - 2003, we were already doing our own Rails, but a tiny | startup in Lisbon does not rock the world the same way. | | However that experience lived on and gave birth to OutSystems. | int_19h wrote: | You can't really get full-fledged closures without ditching the | fundamental concept of Tcl, which is that "everything is a | string". It's the same problem as OOP, or rather, object | lifetime management - you can have that in Tcl, but only as | long as you manage the lifetimes manually. For closures, this | negates most of the benefits they provide. | lilyball wrote: | It would work if they basically copy the current value of the | identifiers (i.e. by-value, not by-reference). Or by | capturing the procedure context. You can synthesize the | variable capture by hand but that would indeed force | everything into a string, which is a potential performance | issue and would also break any sort of automatic lifetime | management. | | 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. | pooryorick wrote: | [list apply {args body} $value1 $value2 ...] can be used to | capture values without actually generating a string because | even though conceptually a list is a string, it's actually | stored internally as a list. | int_19h wrote: | The basic problem is, how do you even know that something | is a variable reference? Remember, _everything_ is a | string. This means that the body of the lambda is also a | string. Now you can require that it 's an eval'able string | at the point of creation, and parse it to identify any $var | references. But you can only do that for the topmost level | of the lambda, because it can contain nested strings - and | you don't know which of those strings are code, and which | aren't (since it's really the command to which the string | is passed that decides to treat something as code or not). | | 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. | rightbyte wrote: | > The basic problem is, how do you even know that | something is a variable reference? | | Isn't that by convention? Like there is a "upvar" to grab | values of the prior stack. | int_19h wrote: | "upvar" is explicit, there's no guesswork involved there. | But how would you handle a lambda with a body like this? | 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. | verifex wrote: | It's not dead yet. There's still AOL Server [1] and there's at | least one game [2] that uses TCL that is online. :) | | 1. http://www.aolserver.org/ 2. http://www.carnageblender.com/ | doublerabbit wrote: | Long live aolserver, Naviserver [1] is the fork that's still | in very active development. | | 1. https://wiki.tcl-lang.org/page/NaviServer | specialist wrote: | Imagine the timeline where Tcl, Scheme, xlisp, or any of the | dozen other existing, mature, available, non-turrible | programming languages was chosen for DHTML. | | 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. | pcwalton wrote: | The Web would definitely not be better had Tcl been the | language of the Web instead of JavaScript. At least JS has | working closures. | teleforce wrote: | Tcl is one of the most underrated programming languages. I have | a friend who is working at Intel as tool development engineer | (equivalent to software engineer), and Tcl is being used | extensively at Intel for chip tooling and design since a very | long time. | | 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. | enygmata wrote: | Tcl is also at the heart of some F5 Networks products | tverbeure wrote: | As a tool development engineer, it's only normal that your | friend is using Tcl extensively: there is no other option. | | 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. | evancox100 wrote: | I feel like there is an opening for an EDA company or | startup to really embrace Python and provide a Python | interface / command line to their tooling. | synergy20 wrote: | Tcl is deeply rooted in EDA and chip design industry, too | many code were written with it. It's like C++, no matter | how fancy/modern rust is, there is no way it's going to | replace C++ for the next few decades. | | 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. | tverbeure wrote: | I don't think that opening is there. Tcl may be a | terrible scripting language, its usage is not a factor in | the value of this or that EDA tool. | | 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.) | evancox100 wrote: | I think you are probably right, it is not a make or break | factor. Especially when it comes to back-end flows, | PPA/TAT/capacity/design closure are the key metrics and | the big 2.5 have large moats in these areas. | | 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.) | _ph_ wrote: | There is Python support in some EDA frameworks, but | especially in the digital domain, Tcl is still the gold | standard. On the one side this means there are tons of | Tcl code around and any experienced engineer is well | versed in Tcl. Also, electrical engineers are usually | very focussed on electric engineering. While being being | very intelligent, they are often not into programming, so | keeping things very simple is an advantage to them. | lilyball wrote: | I haven't gotten around to looking into Oil Shell. Is it | actually drawing any inspiration from Tcl? The "A Tour of the | Oil Language" page[1] references Ruby and Python but not Tcl. | | [1] http://www.oilshell.org/release/latest/doc/oil-language- | tour... | teleforce wrote: | Not yet but I've mentioned to Andy (Oil Shell author) | regarding the importance of adding command features into | Oil Shell and he is actually looking into it [1]. Hopefully | he will draw some inspirations from Tcl. Imagine a Cisco | like networking command wrapper on top of Linux OS with | eBPF backend. It will turn Linux into a ready-made | formiddable open source networking OS without the need for | NX-OS [2]. | | 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 | | [3]https://news.ycombinator.com/item?id=27167762 | | [4]https://dlang.org/spec/expression.html | lilyball wrote: | TIL looks interesting, but also both too simple and too | complicated. What's the difference between a SubList and | a SimpleList? Why does it require SimpleLists instead of | using variadic arguments (e.g. why [math ($a + $b)] | instead of [math $a + $b])? And why does the author | explicitly disallow multiple spaces in a row outside of | indentation when this is a purely artificial limitation | and does not simplify anything?[1] | | 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. | blacksqr wrote: | Re [1]: the libraries that delete an object when it goes out of | scope use Tcl's built-in "trace" command, which lets you | execute code when a command terminates or when a variable is | deleted, among other events. So no, it's all done in pure Tcl. | lilyball wrote: | Oh it looks like I misremembered. I thought the API I had | used was something like `set doc [foo parse $input]` and the | document would go away when the variable does. I found it, | it's the tDOM library, and it was actually `dom parse $xml | doc` that does the automatic freeing, whereas `set doc [dom | parse $xml]` requires manual deletion. So it probably is | using trace. | rkeene2 wrote: | This is how the "defer" [0] command (from tcllib) in Tcl | works. | | [0] https://core.tcl- | lang.org/tcllib/doc/tcllib-1-19/embedded/ww... | isr wrote: | > 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. | | 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 | int_19h wrote: | While we're at it - Tcl-like languages make for pretty decent | embedded scripting solutions if performance is not a major | requirement. There's one called LIL that's literally just a | single .c file (and the accompanying header) for ease of | embedding: | | http://runtimeterror.com/tech/lil/ | pmarin wrote: | My favorite implementations are partcl[1] (600 lines) and | Picol[2] (500 lines by Salvatore Sanfilippo). | | [1] https://github.com/zserge/partcl | | [2] http://oldblog.antirez.com/post/picol.html | int_19h wrote: | So far as I can tell, the reason why they're so small is | because they implement "everything is a string" literally - | so e.g. appending to a list is basically concat. This is good | enough as a proof of concept, and neatly showcases just how | simple the language itself really is; but perf would be | abysmal even by Tcl standards as soon as you get more than a | few dozen items per list. | | 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. | [deleted] | cmacleod4 wrote: | I wrote a blog post last year trying to explain the under- | appreciated radical minimalism of Tcl, and in particular the | decoupling of syntax and semantics - https://colin- | macleod.blogspot.com/2020/10/why-im-tcl-ish.ht... | celeritascelery wrote: | > Tcl is a macro language, it derives from macro-assemblers, the | C preprocessor, and older, text-oriented languages like TRAC | | 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. | theamk wrote: | TCL does not need macros because every function can be a macro. | Here is an answer to your question: 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/jka | | The 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". | celeritascelery wrote: | But that won't work if I am using variables correct? because | {} does not interpolate. | blacksqr wrote: | It will work because the value passed to proc multiline | within the curly braces is treated as a string without | substitutions, that value is then passed to the regsub | command which replaces all newlines in the string with | spaces, then the result is passed to uplevel, which is | basically "eval this string in the scope context where | multiline was called". It's uplevel that does all the | variable substitution, using any values defined in the | scope where multiline was executed. | theamk wrote: | sure it will, "uplevel" will interpolate for you. | | There is a link to online playground, I encourage you to | visit it and try various changes. No installation or signin | required. | blacksqr wrote: | In Tcl newlines only have special meaning at the end of a | command -- at the beginning of a command they're just | whitespace. So you can break up a long line as follows: | | set foo [ | | foofn bar [ barfn baz [ bazfn quz 1 | ] ] | | ] | | Elegant! | mjevans wrote: | I dislike that too about most of the languages which are in | some way white-space sensitive. (Python as the go-to worst | example, but other modern languages where ; or a statement | termination value is optional also fit.) | | 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. | tyingq wrote: | It's a bit odd, because you can skip newlines in many cases. | | This works: #!/usr/bin/tclsh set foo [ | lindex [ expr 2 * 3 ] 0 ] puts | $foo | ahartmetz wrote: | The CMake language has the same absence of syntax, and everything | is a command as well - like assignments with set(). Oh, and all | variables are strings, too like in Tcl. (In CMake, even lists of | strings are strings. Don't ask.) | | The CMake language was created in a haphazard way as well, with | some other important problems that Tcl probably doesn't have. | Y_Y wrote: | CMake is the modern MUMPS. | denton-scratch wrote: | Article doesn't do a good job of explaining why Tcl syntax isn't | weird. | | 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. ___________________________________________________________________ (page generated 2021-11-08 23:01 UTC)