[HN Gopher] Why Tcl?
       ___________________________________________________________________
        
       Why Tcl?
        
       Author : elvis70
       Score  : 167 points
       Date   : 2023-06-20 13:01 UTC (10 hours ago)
        
 (HTM) web link (gist.github.com)
 (TXT) w3m dump (gist.github.com)
        
       | gilbetron wrote:
       | 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.
        
         | keithalewis wrote:
         | 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.
        
           | cpeterso wrote:
           | Tcl may not be strongly typed, but it is "stringly typed". :)
        
           | kevin_thibedeau wrote:
           | Tcl hasn't been string based for over 20 years. It's time for
           | this myth to die.
        
             | tyingq wrote:
             | 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.
        
               | kevin_thibedeau wrote:
               | That wiki page has been around since before Tcl 8. Nobody
               | says lisp is hampered because everything is an S-expr.
        
               | tyingq wrote:
               | > 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.
        
           | zylent wrote:
           | after using expect and TCL heavily for years, I can firmly
           | say they suck at scale.
           | 
           | Ruby https://github.com/ytti/oxidized/blob/master/lib/oxidize
           | d/mo... or TextFSM https://github.com/google/textfsm
           | 
           | are much better options if you need to do a /lot/ of parsing
        
         | 7thaccount wrote:
         | 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).
        
           | girishso wrote:
           | > 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.
        
             | westernpopular wrote:
             | 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?
        
               | charukiewicz wrote:
               | 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/
        
           | 999900000999 wrote:
           | 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.
        
             | ElectricalUnion wrote:
             | 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.
        
       | tmcb wrote:
       | 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.
        
         | monetus wrote:
         | 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.
        
         | phamilton wrote:
         | > 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).
        
           | tmcb wrote:
           | 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.
        
             | arp242 wrote:
             | 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.
        
               | tmcb wrote:
               | 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.
        
       | treis wrote:
       | 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.
        
         | msla wrote:
         | 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.
        
           | treis wrote:
           | 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.
        
             | aidenn0 wrote:
             | In python variables introduced in a loop are definitely
             | accessible outside of it...
        
         | BeetleB wrote:
         | > 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.
        
         | pwg wrote:
         | > 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".
        
       | shrubble wrote:
       | 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.
        
         | AshamedCaptain wrote:
         | 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.
        
       | hfkwer wrote:
       | How about some PowerShell instead?
       | 
       | # Echo command-line input                   $args -join " "
       | 
       | (Yes, it's a single line.)
       | 
       | # Count duplicates in a file                   $lines = @{}
       | foreach ($path in $args) {             cat $path | % { $lines[$_]
       | += 1 }         }         $lines.GetEnumerator() | % { if
       | ($_.Value -gt 1) { "$($_.Value)`t$($_.Name)" } }
       | 
       | # GET request                   param($url)         irm $url
       | 
       | # Parallel GET requests                   $before = get-date
       | $args | % -parallel {             $res = iwr $_
       | $after = get-date             $time = ($after -
       | $using:before).TotalSeconds
       | "${time}s`t$($res.RawContentLength)`t$_"         } -ThrottleLimit
       | 12345         $after = get-date         $time = ($after -
       | $before).TotalSeconds         "${time}s elapsed"
       | 
       | I'm showcasing a few different ways of doing things: using $args,
       | using the param directive; using foreach, or % which is an alias
       | of ForEach-Object; irm for Invoke-RestMethod, iwr for Invoke-
       | WebRequest...
        
         | ptx wrote:
         | No thanks. PowerShell seems to have all sorts of crazy gotchas
         | in addition to the weird syntax.
         | 
         | For example, if I understand correctly, your "cat $path" won't
         | actually work for all filenames, because "cat" is an alias [1]
         | for "Get-Content -Path" which will expand wildcards in the
         | filename [2][3], so you have to know to use "-LiteralPath"
         | instead of you want it to work properly.
         | 
         | And then there's Microsoft's telemetry, which is enabled by
         | default. [4]
         | 
         | [1] https://learn.microsoft.com/en-
         | us/powershell/scripting/learn...
         | 
         | [2] https://stackoverflow.com/questions/33572502/unable-to-
         | get-o...
         | 
         | [3] https://learn.microsoft.com/en-
         | us/powershell/module/microsof...
         | 
         | [4] https://learn.microsoft.com/en-
         | us/powershell/module/microsof...
        
           | hfkwer wrote:
           | A shell language that expands wildcards isn't what I'd call a
           | "crazy gotcha". And let's be real, if you name your files
           | with * or ? in their names, you're just setting yourself up
           | for a bad time.
           | 
           | Weird syntax? Weirder than TCL?
           | 
           | I frankly don't care about the telemetry.
        
           | Riverheart wrote:
           | "<Language> seems to have all sorts of crazy gotchas in
           | addition to the weird syntax."
           | 
           | Says everyone about every language.
        
       | forinti wrote:
       | 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.
        
         | sigzero wrote:
         | 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.
        
         | axus wrote:
         | Yep, what I've always appreciated most about Tcl is ease of
         | using Tk.
         | 
         | Worst way to make a scripted GUI: dtksh
        
         | SPBS wrote:
         | 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?
        
           | mometsi wrote:
           | Sun put money into it in the mid 90s, it was their big cross-
           | platform project before putting everything behind Java.
           | 
           | see https://www.tcl.tk/about/history.html#Sun
        
         | dsab wrote:
         | Its easy to develop, surely, but my style feeling hurts how
         | ugly TCL GUI looks like compared to modern GUIs
        
           | rightbyte wrote:
           | Given the recent trends in "UX" I would regard that as a a
           | feature though.
        
       | IshKebab wrote:
       | 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.
        
         | MrStonedOne wrote:
         | [dead]
        
       | a2tech wrote:
       | 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
        
         | greenpeas wrote:
         | https://wiki.tcl-lang.org/page/How+do+you+say+%27Tcl%27
         | 
         | > It was a good decision to invent tcltest rather than, say,
         | "testtcl". Or, better yet, do not say the latter, at least in
         | English.
        
       | VBprogrammer wrote:
       | 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.
        
         | thenewwazoo wrote:
         | For a company in the rental automobile space?
        
         | IggleSniggle wrote:
         | 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_
        
           | nmz wrote:
           | What would you use instead?
        
             | IggleSniggle wrote:
             | 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
        
           | karl_gluck wrote:
           | 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?
        
           | lanstin wrote:
           | 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.
        
         | jakswa wrote:
         | 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 :)
        
         | jacknews wrote:
         | I think the comparison to bash etc is apt.
         | 
         | tcl is definitely much better, but equally uninspiring.
        
       | eesmith wrote:
       | 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
        
       | waynecochran wrote:
       | 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.
        
       | systems wrote:
       | For me for Tcl to be relevant again its needs
       | 
       | 1. a Package Manager (they sort of already have one called TEA,
       | but its not active as far as I know)
       | 
       | 2. an IDE or a good modes for the popular editors (VS Code,
       | Emacs, Vim, Sublime Text)
       | 
       | For a UI language the absense of a good IDE or editor modes is
       | very strange, you would expect that a Tcl/Tk IDE written in
       | Tcl/Tk (one that also serve as UI framework or scaffolding for
       | other apps) would be its killer app, but there isnt one
        
       | LesZedCB wrote:
       | 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.
        
         | roflyear wrote:
         | 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?
        
       | bit_flipper wrote:
       | 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.
        
       | stealthcat wrote:
       | Because you work in semiconductor industry.
        
         | hoosieree wrote:
         | The best thing about TCL is it's not OCEAN.
        
         | mardifoufs wrote:
         | 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 :)
        
           | mschaef wrote:
           | 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).
        
         | uncertainrhymes wrote:
         | 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.
        
         | jeremy0x4a wrote:
         | Or have an ancient and undying passion for Eggdrop IRC bots.
         | Eggdrop was an introduction to TCL for _dozens_ of us.
        
       | a_wild_dandan wrote:
       | The gist of those examples in TypeScript:
       | 
       | EXAMPLE 1: Echo command-line input
       | console.log(process.argv);
       | 
       | EXAMPLE 2: Count duplicates in a file                   import {
       | readFile } from "fs/promises";         readFile("0.txt",
       | "utf-8").then((text) => {           const frequency: { [line:
       | string]: number } = {};           text             .split("\n")
       | .forEach((line) => (frequency[line] = frequency[line] + 1 || 1));
       | Object.entries(frequency)             .filter(([key, value]) =>
       | value > 1)             .forEach(([key, value]) =>
       | console.log(value, key));         });
       | 
       | EXAMPLE 3: GET request
       | fetch(process.argv[2]).then(console.log).catch(console.error);
       | 
       | EXAMPLE 4: GET parallel requests
       | process.argv.slice(2).map((url) => {           const start =
       | Date.now();           fetch(url).then((res) =>
       | console.log(               `${(Date.now() - start) / 1000}s`,
       | res.headers.get("Content-Length"),               url
       | )           );         });
       | 
       | Using the author's criteria, relative to Tcl, these
       | implementations (to me) are:
       | 
       | 1. Significantly shorter, just as expressive, and familiar to
       | millions of (JS/TS) devs
       | 
       | 2. Fast, owing to Node.js/V8's insane optimization level
       | 
       | 3. Strongly typed
       | 
       | But you know what? I don't care much about terseness or speed
       | when writing scripts. Honestly, the _real_ reason I use TS for
       | scripts is simple: comfort. I 'm comfortable and productive with
       | it. Everything else is just post-hoc rationalization. I'd wager
       | it's the same story for many of these "Why <language/tech>?"
       | posts.
       | 
       | It's perfectly fine to use something simply because you like it
       | -- you're in good company. :)
        
         | bentinata wrote:
         | I used to think POSIX shell scripts are the best. But ever
         | since deno support npm packages directly, running `deno run
         | url-to-scripts` seems really good now. You get readability,
         | types, and library ecosystem.
        
         | vdksbskdb wrote:
         | i frown on anything JS because it always end up requiring some
         | sort of 'npm install' or, shivers, 'npm install -g'. it's just
         | as bad a running a random 4gb java binary with extra steps.
         | 
         | js will only run on users machines or inside a vm without even
         | kvm because we've seen plent ecosystem hijacks and exploits in
         | the wild already. and you can only fool me MAX_INT.
        
           | motogpjimbo wrote:
           | Generally, when you see a package asking you to install it
           | globally with `npm -g i`, you can install it locally with
           | `npm i` and then run it with `npx`. Requesting global
           | installation is either an expression of ego or the author is
           | a Python refugee.
        
         | arp242 wrote:
         | > 2. Fast, owing to Node.js/V8's insane optimization level
         | 
         | But you need to convert the TS to JS, and the TS compiler takes
         | like 3 seconds to start on my laptop (orders of magnitude
         | slower than any other compiler I know, although you can speed
         | it up a bit if you disable type checking, but that, well,
         | removes type checking).
        
           | a_wild_dandan wrote:
           | You don't need a compiler. The vanilla `node` binary works
           | fine with a few trivial syntactic changes.
           | 
           | It sucks that your compiler's slow! Check out `swc` if you
           | prefer speedy compilation.
        
             | arp242 wrote:
             | swc doesn't do type checking, so while useful in some cases
             | it's not really a replacement for tsc.
        
             | tom_ wrote:
             | Does node do static type checking?
        
         | ori_b wrote:
         | I'm pretty sure your examples behave differently from the
         | example programs.
         | 
         | For example, 'console.log' will pretty-print the data
         | structure, rather than a single space separated line, the
         | duplicate counter only reads from one file (with a hard-coded
         | name) and will not correctly handle errors and move to the next
         | file, and your parallel get doesn't seem to print one duration
         | for all requests to complete.
        
           | a_wild_dandan wrote:
           | Ergo the weasel word "gist" of the examples! :) Want variadic
           | arguments? Wrap your code in
           | `argv.slice(2).forEach(mySweetParser).catch()` or whatever.
           | My point wasn't to scrupulously transpile Tcl to TS via HN
           | dialog boxes. I don't have myself _that_ much. My point is
           | just that the real work in those examples can easily be
           | hogged out faster via other languages, so Tcl isn 't an
           | outstanding tool for brevity.
        
         | eesmith wrote:
         | .split("\n")
         | 
         | It looks like this has the same issue as the Tcl code, where
         | the empty string after a terminal "" is treated as a line. I
         | think that is an error in the Tcl.
         | 
         | You'll also need a .catch(err => console.log("dup:", err));
         | 
         | And the console.log(value, key) needs a tab separator.
         | 
         | And a loop over the argv input files.
         | 
         | All minor tweaks which don't detract from your conclusion.
        
       | dangerboysteve wrote:
       | 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!
        
       | NelsonMinar wrote:
       | 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.
        
         | gorjusborg wrote:
         | Similarly, Redis uses TCL for unit testing.
        
           | stevekemp wrote:
           | Well Redis started off being written in TCL.
           | 
           | https://gist.github.com/antirez/6ca04dd191bdb82aad9fb241013e.
           | ..
           | 
           | And of course Antirez has a soft-spot for TCL:
           | 
           | http://antirez.com/articoli/tclmisunderstood.html
           | 
           | Which inspired me to create a (trivial) TCL interpreter in
           | golang. Not perfect, but almost as good as picol:
           | 
           | https://github.com/skx/critical
        
       | dangerboysteve wrote:
       | I just remembered the Decent Espresso machine has its UI written
       | in tcl/tk https://decentespresso.com/
        
       | Pompidou wrote:
       | I have a tcl/tk distribution (now IronTcl 8.6.7) with tcllib on
       | each computer I use since a lot of time. It's very handy : md5
       | and other hash tools ? tcllib. Quick and simple representation of
       | data as graph and calculations ? tcllib. Simple data
       | structuration ? Tcl dicts. String search/substitutions/regex ?
       | pure tcl. batch operations on files/folders ? pure tcl. Easy and
       | fast database with sqlite ? Tcl sqlite lib. Custom menu and app
       | launcher in your desktop ? Pure Tcl. Hex and binary file reading
       | and formating ? Pure tcl. And so on. As a public administration
       | worker, Tcl Tk helped me working very faster for a lot of tasks.
        
       | generalizations wrote:
       | 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.
        
         | IggleSniggle wrote:
         | Honestly I wish all the old awk fanatics had been tcl fanatics
         | instead.
        
       | catminou wrote:
       | I wonder how many folks learned of tcl/tk cause of eggdrop.
        
         | ursuscamp wrote:
         | I learned it originally because of Xircon:
         | https://en.wikipedia.org/wiki/XiRCON
        
       | jll29 wrote:
       | 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).
        
         | giraffe_lady wrote:
         | 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.
        
           | synergy20 wrote:
           | 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?
        
             | nick__m wrote:
             | In tcl strings are first class citizens as everything in
             | tcl is a basically a string.
        
             | giraffe_lady wrote:
             | 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.
        
             | pfix wrote:
             | 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.
        
       | boringuser2 wrote:
       | 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.
        
         | jrm4 wrote:
         | So curious as to why this got downvoted -- it feels exactly
         | right.
        
           | boringuser2 wrote:
           | 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.
        
           | DonaldPShimoda wrote:
           | Any sufficiently complex LLM-generated program is
           | (semantically) indistinguishable from garbage.
        
             | boringuser2 wrote:
             | 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.
        
             | jrm4 wrote:
             | Well duh, that's not what you use it for. You use it to
             | generate parts and snippets quicker.
        
             | generalizations wrote:
             | 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.
        
       | lizknope wrote:
       | 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.
        
         | BeetleB wrote:
         | 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.
        
           | doix wrote:
           | > 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.
        
           | i_am_a_peasant wrote:
           | 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
        
           | zwieback wrote:
           | 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.
        
         | Kosirich wrote:
         | Siemens NX uses it for the CAM post-processor customization.
        
         | appleflaxen wrote:
         | What are your thoughts? How do you like it as a language?
        
       | MrStonedOne wrote:
       | [dead]
        
       | malkia wrote:
       | 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.
        
         | LexiMax wrote:
         | 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?
        
       | DonaldPShimoda wrote:
       | > 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.
        
         | lanstin wrote:
         | 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.
        
         | ukuina wrote:
         | Are you saying the lines are blurred, or that there are more
         | tiers of abstraction?
        
           | TillE wrote:
           | 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.
        
       | BiteCode_dev wrote:
       | 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.
        
         | eesmith wrote:
         | The "take command-line input and print it out" in Python is
         | even more succinctly written:                 import sys
         | print(*sys.argv[1:])
        
         | bragr wrote:
         | 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
        
         | karl_gluck wrote:
         | 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 :)
        
         | kazinator wrote:
         | 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*))))
        
       | kajaktum wrote:
       | 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.
        
         | cmacleod4 wrote:
         | "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 ;-)
        
       | o1y32 wrote:
       | The article is so laughable.
       | 
       | 1. Of course "Hello world" takes more lines in Go than Python or
       | Tcl. But that does not mean anything. The "overhead" here will
       | become meaningful for larger scripts/projects, and Go or Python
       | are far more capable of much more complex things than Tcl. This
       | is simply a dumb example.
       | 
       | 2. Other than certain circumstances, I never heard any one care
       | about scripting performance on the ms level. Often not even at
       | 1-2s (which rarely happens anyway). Putting a table out there and
       | say "this is faster by <1ms" is meaningless to anyone other than
       | the author.
        
       | greenpeas wrote:
       | #!/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.
        
         | pwg wrote:
         | > 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]
        
         | AshamedCaptain wrote:
         | 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.
        
           | pwg wrote:
           | 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.
        
         | shrubble wrote:
         | The author is following examples given in a book, however.
        
           | greenpeas wrote:
           | Oh, I missed that. I guess it's alright then. I thought they
           | chose this particular example to "showcase" Tcl by
           | comparison.
        
       ___________________________________________________________________
       (page generated 2023-06-20 23:02 UTC)