[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)