|
|
Log in / Subscribe / Register

Tcl/Tk 9.0 released

The most recent major release of the Tcl/Tk language and graphical-user-interface toolkit, Tcl/Tk 9.0, has been released, a mere 27 years after the 8.0 major release in 1997. There have been plenty of releases in the interim, though, as can be seen in the Tcl chronology. The 9.0 release brings 64-bit data values, better Unicode support, the ability to use zip files as filesystems, a switch to use epoll() or kqueue() where they are available, SVG support in Tk, access to notifications and other desktop-platform services in Tk, and lots more. For more information, see the release notes for Tcl and Tk that can be downloaded as Markdown files from the announcement page. (Thanks to Matt Bradley.)

to post comments

Amazing

Posted Sep 30, 2024 15:05 UTC (Mon) by dskoll (subscriber, #1630) [Link] (5 responses)

Wow. I love Tcl/Tk. The Tk toolkit is really amazing for whipping up quick desktop GUIs, and I think its geometry managers are as good as anything that has come since.

TCL/TK deserve to be better known

Posted Sep 30, 2024 15:21 UTC (Mon) by ballombe (subscriber, #9523) [Link] (4 responses)

the "module" system used in HPC is based on Tcl but most users do not realize the power of the system and how a properly written module file can be reused unchanged for most module (by looking at the path to the module file itself).

TCL/TK deserve to be better known

Posted Sep 30, 2024 16:28 UTC (Mon) by dskoll (subscriber, #1630) [Link] (1 responses)

I agree that Tcl/Tk is sadly under-rated and little-known. It has found a niche in some EDA (Electronic Design Automation) products, but it really deserves to be much more widely used.

Tk is the default GUI for Python

Posted Sep 30, 2024 17:33 UTC (Mon) by gmatht (subscriber, #58961) [Link]

Not many people use Tcl, but Tk is the GUI bundled with Python (though distributions tend to remove it from the base package). I would have thought that the majority of developers would have heard of Tcl (though they might just think of it as the thing you say before Tk).

TCL/TK deserve to be better known

Posted Sep 30, 2024 16:58 UTC (Mon) by devnull13 (subscriber, #18626) [Link]

We used to use modules a long time ago when your $PATH variable could get longer than the limit (circa 1990s on SunOS). My boss always ran into that problem. 🥺 I also fondly remember using the module commands to switch compilers or to temporarily add packages on HPC machines. Time flies, that was more than 15 years ago. 🙂

TCL/TK deserve to be better known

Posted Sep 30, 2024 18:25 UTC (Mon) by joib (subscriber, #8541) [Link]

Nowadays there's Lmod, which is an improved implementation of the modules system, that happens to be implemented in Lua rather than Tcl. And in yet other HPC style environments, containers are increasingly used as a way to provide each app with whatever crazy combination of libraries it needs rather than needing a module system to provide everything under the sun.

Also, nowadays many HPC admins no longer write their mod/Lmod files manually, but use 'meta build systems' like spack or easybuild that generate module files as part of the build.

That being said, the original Tcl module system was awesome back in the day and was pretty essential in many HPC sites.

Python/Tkinter?

Posted Sep 30, 2024 15:22 UTC (Mon) by yodermk (guest, #3803) [Link]

Wow. I never wanted to use Tcl, but used Perl/Tk in the 1990s, and was pretty impressed. Don't want to use Perl either now, but Python/Tkinter might still make some sense. Hopefully these improvements make it there.

Stability

Posted Sep 30, 2024 18:36 UTC (Mon) by malmedal (subscriber, #56172) [Link] (4 responses)

Nice, the oldest program that I use frequently is written in Tcl/Tk, unlike programs in certain other languages, it hasn't needed to be rewritten every couple of years...

Stability

Posted Sep 30, 2024 20:11 UTC (Mon) by dskoll (subscriber, #1630) [Link] (3 responses)

9.0 actually broke my TkRemind calendar app, which was pretty annoying. Tcl 9.0 no longer replaces ~ with your home directory in filenames. I used that quite a bit out of convenience. But that's the first time a new release of Tcl has broken that piece of code.

Stability

Posted Sep 30, 2024 20:42 UTC (Mon) by malmedal (subscriber, #56172) [Link] (2 responses)

I think it's acceptable when it is a security fix, it's to avoid problems like:
cd /tmp
foreach f [glob *] {file delete -force $f}
This will not be fun with a file named ~ in that directory.

Stability

Posted Sep 30, 2024 23:43 UTC (Mon) by dskoll (subscriber, #1630) [Link]

Aha, thanks. I didn't realize it expanded ~ even after doing variable expansion. I thought it had to be a literal ~. Now the change makes much more sense.

Stability

Posted Oct 1, 2024 6:53 UTC (Tue) by epa (subscriber, #39769) [Link]

That doesn't even have to be thought of as a security fix. It is simply a bug (in any program that uses this idiom). Just as programs that do something weird when confronted with filenames containing a space are buggy. It can be hard to convince developers that it's a bug ("don't do that").

a bit of a blast from the past for me

Posted Sep 30, 2024 19:47 UTC (Mon) by zwol (guest, #126152) [Link] (3 responses)

I bounced off Tcl really hard in the 1990s -- version 7.4, which was painfully slow at arithmetic, and the boss wanted me to use it for number crunching, so that went exactly how you'd expect -- I have no idea what it's like now, but I have to say it's nice to see a project that understands the proper length of time that should elapse between major version bumps.

a bit of a blast from the past for me

Posted Sep 30, 2024 20:12 UTC (Mon) by dskoll (subscriber, #1630) [Link] (2 responses)

Tcl prior to 8.0 was very slow... internally, everything was a string so it would interpret everything anew. 8.0 introduced a bytecode compiler which sped some things up quite a bit.

But for math-intensive code, Tcl is the wrong language, unless you use an extension that does the math in C or assembler.

a bit of a blast from the past for me

Posted Oct 2, 2024 14:28 UTC (Wed) by anselm (subscriber, #2796) [Link] (1 responses)

The original idea behind Tcl was that one would use it to piece together applications where the heavy lifting would be done in C code (or similar). Tcl makes it really easy to export C functionality to Tcl, and Tk made it really easy to put a GUI on top.

Back in the day when DVI files were a thing for (La)TeX output, I wrote a Tcl/Tk-based DVI file previewer which essentially supported DVI as a format for Tk canvas “image” items (with the DVI interpreter, font handling, etc. implemented in C). This enabled some cool features like being able to display facing pages like PDF viewers do today, or an “overview” mode where you could look at a large scaled-down grid of pages to check the placement of floats and page breaks. It was also (obviously) possible to combine DVI output with other Tk canvas items on the same canvas, add hyperlinks, etc. Performance was not a problem at all – even on a 486DX33 it was absolutely feasible to implement an xdvi-style “magnifying glass” based on Tk event handling, with the magnified output in a scratch Tk canvas in an override-redirect window that panned to follow the mouse pointer on the original document. Certainly from the magnifying glass feature you couldn't tell that you weren't using xdvi.

Tcl/Tk is one of the most underrated languages/GUI frameworks in the business and its internals are incredibly well engineered for what it does. It had reasonable Unicode support way earlier than most other mainstream languages, and the Tcl 8.x byte compiler, when it arrived, took care of most of the performance issues that were due to the previous “everything is a string” model. It's great to see that Tcl/Tk is still kicking.

a bit of a blast from the past for me

Posted Oct 2, 2024 18:01 UTC (Wed) by dskoll (subscriber, #1630) [Link]

Yes, I agree. I embedded Tcl in a couple of projects and its internals were a pleasure to work with. Well-designed, and importantly, very well-documented.

In a later project, I embedded Perl and was pretty shocked and disgusted by the Perl internals. I think John Ousterhout had a fantastic vision for Tcl/Tk and was an excellent software designer, and those great fundamentals have carried on throughout the project.

iRule Ok!

Posted Sep 30, 2024 21:10 UTC (Mon) by hisdad (guest, #5375) [Link] (2 responses)

I use it frequently in small amounts. The iRule System for the BIG-IP product will run TCL fragments on data events.
Very useful and very fast. However I'm glad it was just small fragments as trying to write functions (procs) is opaque I never did figure upvalues out..

https://clouddocs.f5.com/api/irules/WhatIsAnIRule.html

IOS-too

Posted Sep 30, 2024 23:22 UTC (Mon) by raven667 (subscriber, #5198) [Link]

I think Cisco IOS has some facility to run TCL as an embedded scripting language but I've never seen it used, I think most places just automate the CLI. We still use TCL as part of Expect for clogin2 (derived from RANCID a long time ago) but with very little ongoing maintenance as I don't know TCL all that well.

A long time ago at a different place we had some Perl/Tk utilities, before Python/GTK existed, which were very responsive, and it might be fun to go back for those who have the time, but all the engineering effort has gone into HTML/CSS/JS instead of Tk, even for local apps with Electron.

Now I was wondering who used scotty/Tkined but I just searched for it and apparently it's still maintained ... by FlightAware (?!)

Tk is weird but neat although the technical preference for embedded scripting languages is usually Lua or Python, not TCL, even though that's what it was designed for, IIUC.

iRule Ok!

Posted Sep 30, 2024 23:33 UTC (Mon) by raven667 (subscriber, #5198) [Link]

Hit send too soon, the other place I remember TCL showing up was in the network processor on the BreakingPoint load simulation appliance (then Ixia, then someone else), so it's possible the F5 used the same kind of processor (maybe Cavium or similar), to simulate hundreds of thousands of devices all speaking HTTP or DHCP or whatever with full TCP sessions and whatnot, capable of saturating 10Gbit line-rate. They had a UI (in Adobe Flash to get a sense of how long ago this was) where you could customize the built-in programs and do some light scripting but I thought there was a way to load your own TCL programs if you have the technical expertise to develop them, but maybe I'm mis-remembering (I don't want to spend the rest of the evening looking up info on a dead appliance platform 8-) but I wonder if anyone else worked on this kind of stuff?

Tcl helped Guile Scheme

Posted Oct 2, 2024 10:35 UTC (Wed) by jem (subscriber, #24231) [Link] (13 responses)

Not everyone was convinced of the excellence of Tcl. From the Guile Manual:

Richard Stallman, as the primary author of GNU Emacs, had a particular vision of what extension languages should be, and Tcl did not seem to him to be as capable as Emacs Lisp. He posted a criticism to the comp.lang.tcl newsgroup, sparking one of the internet’s legendary flamewars. As part of these discussions, retrospectively dubbed the “Tcl Wars”, he announced the Free Software Foundation’s intent to promote Guile as the extension language for the GNU project.

Tcl helped Guile Scheme

Posted Oct 2, 2024 18:07 UTC (Wed) by dskoll (subscriber, #1630) [Link] (11 responses)

I don't know for sure, but I suspect part of Stallman's antipathy to Tcl was its very liberal (MIT-like) license rather than a GNU license. His technical criticisms were either off-base or have been addressed in subsequent Tcl releases.

Anyway, you can read Stallman's criticism and the responses here.

Tcl helped Guile Scheme

Posted Oct 3, 2024 7:44 UTC (Thu) by oldtomas (guest, #72579) [Link] (10 responses)

A Google-free alternative here: https://vanderburg.org/old_pages/Tcl/war/

The whole (IMO very unfortunate) episode became known as the "Tcl War", and yes, I think Stallmann's main beef at the time must have been Tcl's "corporate friendliness" (Stallmann went as far as calling Ousterhout a "parasite" for leaving Berkeley and working for Sun -- this is around 1994, so about the same time). That he pushed technical arguments to the fore must be an instance of that classical "nerd dishonesty" many of us fall into from time to time (I know I do).

On the one hand, Stallmann was a visionary: these days you can see the corporate world gutting free software of all its values and using it to curtail user's freedoms in far more subtle ways than one might have imagined back then.

On the other hand, this episode caused a lot of unnecessary grief. Most of the Tcl community is wary of the GPL and all things FSF to this days.

Oh, another thing: this radical "everything is a string" (affectionately called EIAS in Tcl lingo) made for an incredibly enjoyable C interface: Tcl functions just took argc, argv. This, of course, got lost once Tcl gained a bytecode interpreter with 8.0 (must have been as a guest to Sun, where much more paid hands were available to do that huge work). A typical evolution of languages back then (Guile did something pretty similar).

Tcl helped Guile Scheme

Posted Oct 3, 2024 8:51 UTC (Thu) by anselm (subscriber, #2796) [Link] (9 responses)

This, of course, got lost once Tcl gained a bytecode interpreter with 8.0

That was less the bytecode interpreter than it was the introduction of the Tcl_Obj types, which enabled Tcl data items to have a non-string representation and to hang on to it for extended periods of time. This meant that the interpreter could convert a variable's value from a string to a number and use the numeric value from then on, without converting it back to a string for storage and again to a number if you wanted to use it in a calculation once more.

Of course the bytecode interpreter helped a lot with running Tcl code faster, but the ability to, e.g., store lists as lists (with direct pointer-based access to individual items as opposed to having to parse a long string to locate them every time) arguably had the biggest impact on Tcl performance.

Tcl has various other interesting features, like the idea of subinterpreters, including “safe” interpreters used to run untrusted code, that other languages are still missing (the Python community is now taking a greater interest in subinterpreters, 25 years after Tcl added the feature). In a number of respects the language was way ahead of its time, and it is a pity that – except for some areas such as EDA – it never got the traction it deserved. To think that instead of coming up with a bum language like JavaScript, Netscape could simply have added Tcl to their browser boggles the mind. What a wonderful world this could be …

Tcl helped Guile Scheme

Posted Oct 3, 2024 11:28 UTC (Thu) by mgedmin (guest, #34497) [Link] (8 responses)

I'm not sure what you mean by the Python community's sudden interest in subinterpreters, but, to quote python.org

> CPython has supported multiple interpreters in the same process (AKA “subinterpreters”) since version 1.5 (1997).

Tcl helped Guile Scheme

Posted Oct 3, 2024 13:38 UTC (Thu) by foom (subscriber, #14868) [Link] (7 responses)

Python supported it...brokenly. Only recently is the support actually being fixed.

All of the interpreters ended up incorrectly sharing a lot of mutable python objects, due to deficiencies in the C extension module API design. This started to be addressed in Python 3.5, via addition of new APIs (which modules need to switch to, and even core python itself wasn't doing this properly until recently).

Only in 3.12 can interpreters have their own district global interpreter locks, and thus run in parallel with each-other.

Even still today, the APIs that allow running a callback into python from C application code (as distinct from calling back into Python in the context of a call from Python) are incorrect if there are multiple interpreters. You must somehow ensure you're calling into the correct Python interpreter state. But all the well-lit paths are broken and incorrect -- they assume that either you already have a python interpreter context associated with the current thread, or that there is a single "main" interpreter that you want to use. (See https://github.com/python/cpython/issues/59956)

Tcl's support for multiple (isolated) interpreters, running in parallel, was solid this entire time.

Tcl helped Guile Scheme

Posted Oct 3, 2024 20:04 UTC (Thu) by NYKevin (subscriber, #129325) [Link] (6 responses)

> You must somehow ensure you're calling into the correct Python interpreter state. But all the well-lit paths are broken and incorrect -- they assume that either you already have a python interpreter context associated with the current thread, or that there is a single "main" interpreter that you want to use. (See https://github.com/python/cpython/issues/59956)

Unfortunately, there's just not much that can be done to properly fix that API. The whole point of PyGILState is to provide a convenient way for foreign code to call into Python without having to know any details of how Python has been initialized or configured. From the perspective of this API, you could be calling into a /usr/bin/python process from a C extension, calling into an embedded interpreter from the program doing the embedding, or any number of more complicated cases. In principle, I think you can even call into this API from a ptrace-injected thread.

The obvious problem is that, if the foreign code does not know which interpreter it wants, then the API has no hope of selecting the right one in the general case. And if the foreign code does know which interpreter it wants, it can call PyThreadState_New() etc. instead of using PyGILState. That's marginally more verbose, but frankly not by very much (there would be some marginal utility in a pair of helper functions or macros similar to Py_BEGIN_ALLOW_THREADS, but each would only be two or three lines long). The larger problem is that you need to restructure your C code in such a way that you know which interpreter you want, either because you create it in the first place, or because you arrange for Python to call into you before you call into Python.

Offering this API in the first place was perhaps imprudent in retrospect, but I'm sure there are plenty of cases where it is very useful.

Tcl helped Guile Scheme

Posted Oct 3, 2024 20:19 UTC (Thu) by anselm (subscriber, #2796) [Link]

The obvious problem is that, if the foreign code does not know which interpreter it wants, then the API has no hope of selecting the right one in the general case.

Tcl addresses this by making the first parameter to most of the function calls in its C API a pointer to a Tcl_Interp structure (which contains the state of the Tcl interpreter in question). That way, it is always clear which Tcl interpreter is meant when you call Tcl from your own C code.

This structure is one of the consequences of Tcl being originally intended as an embedded extension language – the application (usually written in C or C++) would create a new Tcl interpreter via the Tcl C API and use that to run Tcl code (which would then presumably use functionality that the application provided to that interpreter in the shape of Tcl commands) –, rather than a free-standing programming language with an escape hatch into C. Later on, when Tcl acquired the capability to load dynamic shared libraries, it became more popular to provide the “application” as a shared library you'd load from tclsh or wish (a tclsh that is already linked to Tk), rather than the other way round by having a C application that brought in libtcl.so.

Tcl helped Guile Scheme

Posted Oct 4, 2024 3:12 UTC (Fri) by foom (subscriber, #14868) [Link] (4 responses)

Yes, perhaps the best way to fix the Python GILState APIs is to simply deprecate them and recommend an interpreter-aware alternative.

ISTM that a lot of the time, C code will be doing something like invoking a python function callback pointer which had been recorded in the past (potentially on a different thread). It would be "easy" for such code to record the interpreter pointer at the same time as recording the function pointer. Or, at least, it would be if there existed proper documentation of the requirement to do so, and demonstrating how to do so.

Tcl helped Guile Scheme

Posted Oct 4, 2024 18:46 UTC (Fri) by NYKevin (subscriber, #129325) [Link] (3 responses)

It is documented, albeit badly (IMHO). See https://docs.python.org/3/c-api/init.html

Unfortunately, the correct procedure is rather path-dependent and can be complicated in some edge cases, which is probably why the PyGILState functions exist. Here are some examples:

* If Python previously called into you from the same thread, then that thread would usually be managed by Python, and so you probably already have the GIL. Then there would be nothing to do. The only exception I can think of is if you called into Python first (and then it called you back), which implies that you already figured out how to acquire the GIL, so just do whatever you did again.
* If Python previously called into you from a different thread, then you can use PyInterpreterState *interp = PyInterpreterState_Get() to get the current interpreter, and then (on the new thread) call PyEval_RestoreThread(PyThreadState_New(interp)) (error checking elided). When you're done calling into Python, you will probably want to call PyThreadState_Clear(PyThreadState_Get()); PyThreadState_DeleteCurrent() to free the object created by PyThreadState_New() (and implicitly release the GIL). If you want to keep it around for multiple calls into Python, you can use PyEval_SaveThread()/PyEval_RestoreThread() to release and re-acquire the GIL in the usual manner (and you can also use the Py_BEGIN_ALLOW_THREADS convenience macro), but you should eventually free it when finished calling into Python. You need a separate thread state object for each thread that will call into Python (technically, you need one for each thread-interpreter combination, but I'm assuming you're not planning to interleave interactions with multiple interpreters on a single thread, because then you have to use PyThreadState_Swap() and the complexity really starts to make your code hard to read).

Frankly, those two bullets cover the vast majority of "real" use cases. But for full feature parity, there's a long tail of other cases to consider:

* If Python did not previously call into you at all, then you have a couple of further options. You could use the "main" interpreter, which is the first interpreter initialized for the process, as returned by PyInterpreterState_Main(), but that's really only suitable if you're not going to interact with any pre-existing Python objects and just need an arbitrary interpreter. In that case, it is probably preferable to create your own private sub-interpreter instead, preferably with its own private GIL (which you can do by acquiring the main interpreter's GIL and then using Py_NewInterpreterFromConfig(...) to create the sub-interpreter). OTOH, creating lots of tiny interpreters is probably not optimal either, so there's a certain amount of nuance here. You may need to experiment with different setups and benchmark the performance. Creating a private interpreter is most likely to be worth it if you know that the rest of the process is making extensive use of the main interpreter (or some sub-interpreter which shares the main's GIL), and least likely if you're the only code in the whole process calling into Python.
* The other possibility is that you know which interpreter you want, because you created it in the first place. But then this reduces to the "Python previously called you from a different thread" case, since creating an interpreter puts your thread into (more or less) the same state as if Python just called into it from that interpreter. It also implicitly releases the parent interpreter's GIL (if you request a separate GIL for the child interpreter), so you need not worry about doing that.
* PyGILState_Ensure() can also be called recursively if you do not know whether you hold the GIL, and so for full parity, we need to have a way to check whether you have the GIL already (to avoid self-deadlock in the case that you do have the GIL). You can use PyGILState_Check() for that, and unlike the rest of the PyGILState API, this ought to be reasonably compatible with multiple interpreters. That's because it is reading the same thread-local variable that the rest of the PyThreadState API interacts with, so it should not "care" whether you are acquiring the GIL via PyGILState or with the interpreter-aware functions. The caveat is that it is possible to clear this variable without actually releasing the GIL (e.g. with PyThreadState_Swap()), in which case this function can lie to you. So don't do that and then try to query whether the GIL is held - PyThreadState_Swap() requires holding the GIL anyway, so I'm not entirely sure there's even a use case for doing this in the first place.
* Believe it or not, we're still not done, because recursive calls to PyGILState_Ensure() can be interleaved with the rest of the PyThreadState API, including PyEval_SaveThread(), so it also has to check for that case explicitly and re-acquire the lock if it has been released since the last call. I'm... not really sure why you would do that, but apparently it is a thing you can do.
* Note also that Python's thread-local storage API does not require holding the GIL to use, and supports arbitrary (void*) types, so you can record additional information there if it is useful to do so (which is exactly how PyGILState works internally - it maintains a counter of how many times you have called into it in order to figure out when to destroy the thread state, and this system is even designed to avoid destroying manually-created thread states so that it can be safely interleaved with PyThreadState_New() and company).

Fair warning: I have read the documentation for these functions. I have not actually tried to write code against them. I did read some of CPython's source code to spot-check a few points of uncertainty, and I'm fairly sure that most if not all of the above is basically correct (in particular: PyGILState_Ensure() does indeed call PyEval_RestoreThread() to acquire the GIL if necessary, so I'm reasonably convinced that it is legal to create a new thread state from scratch and "restore" it), but it is always possible that I have missed something.

Support for sub-interpreters

Posted Oct 5, 2024 11:26 UTC (Sat) by cgm (guest, #173850) [Link] (2 responses)

Wow! That's a pretty good argument for using Tcl!

Support for sub-interpreters

Posted Oct 6, 2024 8:28 UTC (Sun) by NYKevin (subscriber, #129325) [Link] (1 responses)

Yes, but then I have to learn a new language. I can't throw a stone without hitting three Python scripts written by random people, so I have to know Python.

Support for sub-interpreters

Posted Oct 8, 2024 14:43 UTC (Tue) by dskoll (subscriber, #1630) [Link]

Tcl is a very easy language to learn. Most experienced programmers could learn it in a day or two.

But yes, given the relative popularity of languages, knowing Tcl isn't much of an advantage wrt getting work or understanding other software.

Tcl helped Guile Scheme

Posted Oct 17, 2024 5:54 UTC (Thu) by ceplm (subscriber, #41334) [Link]

And started one of longest variations on “Surely …” skeleton joke https://mcepl.fedorapeople.org/tmp/emacs-guile.jpg

Old friends

Posted Oct 3, 2024 1:03 UTC (Thu) by jkingweb (subscriber, #113039) [Link]

I used Tcl (both with and without Tk) quite a bit 10-15 years ago, but not recently. It's nice to know it's still improving, if I ever need it again, though I always did find the Tcl syntax awkward to read. It was wonderful for writing Tk layouts, though!


Copyright © 2024, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds