Hacker News new | past | comments | ask | show | jobs | submit login
TclTutor 3: Computer aided instruction package for learning the Tcl language (msen.com)
56 points by teleforce on Feb 14, 2022 | hide | past | favorite | 38 comments



I have always found the man page for TCL to be an amazingly concise description of the language.

https://manpagez.com/man/n/Tcl/


Seriously, why aren't more manpages like that.

It even looks good, and I say that as someone who has a strong distaste for plain text. It reminds me of the most impressive linguistic feat someone's ever seen (although this one actually uses extra spaces...): https://news.ycombinator.com/item?id=28651093


Note that a web-enabled version can be found at the end of page https://wiki.tcl-lang.org/page/Tcl+Tutor


Is there a tcl implementation targeting javascript that has upvar and uplevel and can access javascript objects?


Can anyone remind me what Tcl is good for anymore? I know a lot of EDA tools use it as the backend for builds but once the software writes the Tcl script for me, I've never had to make any changes to it more complex than variable names or options.


What is it good for, or what is it used for? I think Tcl's biggest downfall is the fact that it suffers from Excel syndrome in that It works well for a small set of problems and OK for a bigger set of tangential problems.

Tcl is Tool Command Language, and it's pretty good at routing commands to all of your JTAG, GPIB, Serial port, and whatnot devices. It has a REPL that is easy to use, and sits in the same runtime as all of your code. You can kind of think of it as a shell terminal for your devices. It's also apparently pretty compact all things considered. But it's typing is about as strong as wet toilet paper, which is cool when you have commands to send, receive, and parse out. But since it's also a programming language, you get into situations where someone writes all of the code to communicate with all of the devices in a nice little mini-library for everyone else to use. Since Tcl is a programming language, everyone is expected to develop all of the test and debug code in TCL.

For some projects, we'll prototype a feature in Tcl, but the firmware implementation will be way simpler and more concise. That's mostly because doing anything with an array, or any type of math function requires a mess of syntax. The quintessential example would be incrementing a value in an array. In C, it would look like:

myArray[i]++;

But in Tcl, it goes a little something like this:

lset myArray $i [expr [lindex $myArray $i] + 1]

Now imagine doing things with descriptive variable names and it gets pretty messy.


To add to the confusion what TCL calls arrays are not what other languages call arrays.

The above syntax is needed for lists, not arrays.

If you want to increment a value in a TCL array all you need to do is:

    incr myArray($i)
However that array is basically a dictionary, a hash map of (integer in this example) keys to values.


TCL associative arrays are hash maps that have to be global. They are definitely one of the worst part of the language.

Most people use dicts on modern TCL instead.


It is homoiconic without parenthesis soup. It also supports removing commands to the point of being non-Turing complete. That makes it useful as a configuration language for non-trusted input that can be extended as needed.


I've been writing a lot of lisp lately, and I don't know that homoiconicity is in and of itself a virtue. It's nice to have, I suppose, but I don't see what it really brings to the table other than a time-saving hack for reading configuration from disk.


I don't think homoiconicity itself is the most important thing. I think the real power of Lisp comes from a bunch of other features, and a non-homoiconic language would be approximately equal in power to Lisp if it had these features:

1) A public API for manipulating the AST in the standard library. Most languages have some AST API defined as internals of their compiler/interpreter, but it is a private API, not a public API in their standard library. (Lisp's AST is almost trivial; but a language could have some kind of complex ADT-based or object-oriented AST and it would still be okay, so long as the AST is a public API in the standard library.)

2) The AST should be extensible, so you can define new types of nodes.

3) Ability to write arbitrary code (compile-time macros) which gets executed at compile time, and which can read the AST, and generate a replacement AST.

4) Compile-time macros are written in the same language (or almost the same language) as runtime code, rather than some special language (compare the C preprocessor to C).

5) Some form of syntax extensibility

6) Code to execute at compile-time, new AST node types, syntax extensions, etc, can be defined in the same program which uses them, as opposed to being segregated to some kind of "compiler plugin" with some kind of special build process

7) Some kind of "quotation syntax", where you write some code, and instead of actually being compiled, instead code to generate its AST is compiled. For example, 1+1 might evaluate to 2, %ast(1+1) (to pick a possible syntax at random) might evaluate to the AST for 1+1.

8) Some kind of "backquote syntax", to make it easy to write code templates (this is basically just (6) with ability to make substitutions in a hygenic way).

9) All of the above should be able to expressed with syntactic succinctness. Don't be afraid to add special syntax, or even some embedded DSLs, if it makes the above easier to express. (For the language designer/implementor, much of this may simply be dogfooding point 5 above.)

Now, homoiconicity means Lisp can give you (1)-(9) with less work (for the language implementor) than a non-homoiconic language might require. But not everyone likes the simplistic syntaxes which homoiconic languages tend to have, and there is no reason why a language with an Algol-like or C-like or Pascal-like syntax couldn't give you (1)-(9) as well, albeit with a bit more work. Indeed, if you took any existing language and added (1)–(9) to it (if any of them weren't already there), and made sure to do it in an easy to use way, you'd basically end up with a language roughly equivalent to Lisp in power.


It's the fastest way to write an app with a GUI and you can easily make a Windows executable with only an 8MB overhead (with freewrap).


The test suite for SQLite is written in Tcl. It's also an option for customizing Fossil SCM installations.




Certainly a trend to move away from it.

For example, Amira is a package that has been around about 30 years and uses it to script rendering. On the other hand a competitor (Carl Zeiss), a decade ago did a rewrite of their software and choose python (among others) as a scripting language. Nikon also developed their own language that resembles basic/C#.

Asking your users to script in TCL rather than something like python is sadistic, and a position advocated by aging neckbeards.

https://www.thermofisher.com/us/en/home/electron-microscopy/...


Eh, I don't know. I wouldn't choose Tcl today for such a use case, maybe Lua. But you could certainly do worse than Tcl. Like a half-thought out custom language. Anyone ever coded nastran DMAP? Or Tex macros? I'd be ecstatic to have TCL over that.

I've seen a materials testing machine whose method to script custom test sequences was a "programming language" that was displayed as text but you couldn't actually type things in. You'd have to select constructs such as a for loop or conditional from a drop down box, then a dialog would appear asking you for the parameters of the loop (start, end, etc).

Actually, I think I even prefer Tcl to Excel's VBA.


> Asking your users to script in TCL rather than something like python is sadistic, and a position advocated by aging neckbeards.

Right. It's almost impossible to reason about a language that has no meaningful grammar. Finding bugs is hard, automatically finding problems nearly impossible.

Tcl did give us one important thing -- Tk -- via `wish`, which was an important step in informing how people might want to add GUIs to scripts.

But actually still committing to teach it in this day and age is really perpetuating bad habits when there are better options out there -- even PowerShell is a better choice.


See https://news.ycombinator.com/item?id=4120200 article and discussion from 2012.


Tk


Moreover, every Python installation with Tkinter has Tcl built in. You can directly interact with that Tcl interpreter from the Python side.


“Tcl tends to get ported to weird places like routers.”

-Larry Wall (inventor of Perl), on Usenet.


Some major FPGA tools still use it.


TCL is also used in a lot of bots


[flagged]


Some languages have rather simple core syntax, such as Tcl, Lisp, Forth, M4

Other languages have much more complex core syntax, for example C family languages such as C or C++ or Java. Certain languages, such as COBOL or Perl, are at the extreme of core syntax complexity

Separate from the core syntax, we can also speak of "non-core syntax" (which is expressed in terms of the core syntax), which can itself be quite complex whether or not the core syntax is – look at how complex many Tcl commands are; or consider some rich fluent Java API; or the Common Lisp loop macro

You seem to be equating simple core syntax with no syntax. No language has no syntax; a language without syntax could not be a language.


I said nothing at all about syntax; of course it has syntax.

Does Tcl have a grammar? There is a distinction and it is not irrelevant; you will run into the consequences of it.

Markdown has syntax -- but no official grammar. I would not (sorry Mr Gruber) grant Markdown the privilege of being called a language in the same breath as even HTML. Markdown is a syntax looking for a grammar.

So is Tcl. So the definition of Tcl is "what the Tcl interpreter can parse". Like the Apache config file "format" is defined only by what Apache can parse.

(Curious to be downvoted for expressing what was -- twenty five, twenty years ago -- quite a big deal in scripting language circles. Tcl's lack of a grammar up against Scheme, Lisp, etc., was a point of some contention. Either way it is precisely why sane developers do not use Tcl.)


> Does Tcl have a grammar? There is a distinction and it is not irrelevant; you will run into the consequences of it.

Aren't syntax and grammar synonymous? Or, if not exactly the same thing, essentially two sides of the same coin?

In my mind, a syntax is a set of well-formed formulas, a proper subset of the Kleene star of the language's alphabet. And a grammar is basically the same thing. I suppose, beyond being a mere set of WFFs, both are also a mapping from formulas to some kind of tree structure; if we can give the set of WFFs a recursive definition, then a tree structure falls out of it naturally. But, Tcl obviously has a WFF-set and a tree structure. (Although, there are also different levels of WFF-sets – the set of all syntactically/grammatically valid C programs is a proper superset of the set of all semantically valid C programs – a C program which calls an undefined function might be said to be syntactically but not semantically valid – and surely the same point holds for Tcl as well.)

> Markdown has syntax -- but no official grammar.

If Markdown has "no official grammar", it is because there is not one thing called Markdown, there are many. It is many sets of well-formed formulas, which are very disjoint. I suppose almost every language is many rather than one, because every implementation of a language adds a slightly different set of non-standard extensions; but in languages such as C, those differences are confined to relatively narrow areas (such as pragmas, attributes, reserved names, etc); in languages such as Markdown, the syntactic differences between different implementations will be much more extensive, so much so that we are really talking about a family of related languages (flavours as they say), rather than a single one.

> So is Tcl. So the definition of Tcl is "what the Tcl interpreter can parse".

The core syntax of Tcl is reasonably fixed. An independent implementation can be written to accept exactly the same core syntax as the reference implementation does, without any great effort.

The non-core syntax is (near-)infinitely flexible, but I could say the same thing about C or Java. In Tcl, I can define (near-)arbitrarily named commands that accept (near-)arbitrarily named arguments; in C/C++/Java/etc I can define (near-)arbitrarily named functions/methods which accept (near-)arbitrarily named arguments, (near-)arbitrarily named structs/classes/etc which have (near-)arbitrarily named fields, etc.

> Tcl's lack of a grammar up against Scheme, Lisp, etc., was a point of some contention.

That claim makes zero sense to me. Tcl and Lisp have core syntaxes based on rather different principles, but both have a grammar, and I don't think there is any sensible way in which you could say that one has more of a grammar than the other.


> Aren't syntax and grammar synonymous? Or, if not exactly the same thing, essentially two sides of the same coin?

No. (Syntax is a subset of grammar.)

> If Markdown has "no official grammar", it is because there is not one thing called Markdown, there are many.

No, it's also because it's a pattern-based preprocessor. There are efforts to produce Markdown grammars; some have been done.

> That claim makes zero sense to me.

My claim that it was a point of contention? It really was.

> The non-core syntax is (near-)infinitely flexible, but I could say the same thing about C or Java. In Tcl, I can define (near-)arbitrarily named commands that accept (near-)arbitrarily named arguments; in C/C++/Java/etc I can define (near-)arbitrarily named functions/methods which accept (near-)arbitrarily named arguments, (near-)arbitrarily named structs/classes/etc which have (near-)arbitrarily named fields, etc.

No, these are not the same.


>> Aren't syntax and grammar synonymous?

> No. (Syntax is a subset of grammar.)

Your answer does not agree with dictionary definitions, common usage, or linguistics terminology.


Syntax is part of grammar.

Not all of it. They are not interchangeable or two sides of the same coin. That's all. You need syntax to then establish a grammar.

We're talking about a programming language here, of course.

Admittedly, you could say that Tcl is a language in the sense that english is (I was genuinely just snarking in my original comment). Because Tcl (unlike Java or C or Forth or Lisp) is context-sensitive -- the only way to know if a Tcl program uses its syntax correctly is to run it!

With Java/Forth etc., you can tell whether the syntax is being used correctly because these languages have a context-free grammar. This has advantages.

Above all these criticisms are why I think people should not learn Tcl as a serious endeavour if it can be avoided; it should be left to history with perl4.


> Because Tcl (unlike Java or C or Forth or Lisp) is context-sensitive -- the only way to know if a Tcl program uses its syntax correctly is to run it!

I mentioned in my other comment how Lisp and Java are much closer to Tcl than you think they are. But that's true of Forth as well. Forth IMMEDIATE words are equal in power to Common Lisp reader macros, they also allow you to define arbitrary custom syntax – you can even define some custom syntax and then immediately start using it. Just like Common Lisp, it is impossible to know whether a Forth program uses its syntax correctly without running it through a complete Forth runtime environment.


Where are you supposedly deriving your definitions from?


I see your "supposedly" and I'm done with you.


> No. (Syntax is a subset of grammar.)

Can you elucidate what you see the relationship between them as being?

> No, it's also because it's a pattern-based preprocessor.

What do you mean by that? Why does being a "pattern-based processor" imply something has "no official grammar"?

> There are efforts to produce Markdown grammars; some have been done.

So, if people have produced grammars for it, it has a grammar, no?

> No, these are not the same.

How and why are they different?


> Can you elucidate what you see the relationship between them as being?

Grammar covers the correct use of the syntax of a language. With syntax alone you cannot know whether a program is a correct use of a language -- that is, it will parse or compile, even if its output is nonsensical. A grammar lets you do that.

So for example an unambiguous grammar is essential to being able to translate higher level language into assembly language.

> What do you mean by that? Why does being a "pattern-based processor" imply something has "no official grammar"?

Can you parse and transform arbitrary HTML correctly with only regular expressions? The answer as I am sure you will know is no. That is your answer here too.

> So, if people have produced grammars for it, it has a grammar, no?

I don't know if any Markdown grammar exists that expresses all of what you can do in the reference implementation of Markdown, so *shrug*. Maybe, maybe not. The fact that it has no deliberately designed grammar is an interoperability problem though.

> How and why are they different?

Because you are comparing extending semantics within what is allowed by the grammar (writing functions in the programming language it concerns) (e.g. in Java), and extending the interpreter itself (Tcl as a "language" changes according to which extensions are compiled in, and the extensions determine what the symbols mean).

The fundamental question here is this:

Can a program conclude that a Tcl program will parse correctly (even if the code itself has errors) without running the specific Tcl interpreter for which it is designed (or at least without knowledge of the implementation of its extensions)? No, it essentially cannot.

That is what a grammar gives you. You can stare at a bit of C code you do not understand and at least say "it is valid C". And so can another program (a static analyser/explorer, a linter, etc.)

More difficult with Tcl. (And perl4, for example)


> Grammar covers the correct use of the syntax of a language. With syntax alone you cannot know whether a program is a correct use of a language -- that is, it will parse or compile, even if its output is nonsensical. A grammar lets you do that.

Suppose I am writing a Pascal compiler. I might start with a grammar for Pascal, expressed in EBNF. I might write a parser from that grammar, either by hand, or by using some parser generator. My parser converts text (or a sequence of tokens generated by an independent lexical analysis stage) to some kind of parse tree or abstract syntax tree.

Since Pascal is a statically typed language, I also need to write some code to do type-checking. If you look at a tutorial on writing a compiler, you might see this presented as a subsequent compilation stage, after parsing is complete. It takes the AST and symbol table, annotates it with type information (possibly even doing type inference), and checks various rules are obeyed.

And, an EBNF grammar doesn't tell us how to do it. Generally you'd either express it informally, or if you were going to use some kind of formalism, you'd use a rather different formalism from those in which programming language grammars are commonly expressed. There are "typed grammar" formalisms which combine type-checking into parsing, but you don't see them commonly used by people implementing programming languages in the real world. In my experience they are mainly popular in academia (and I've seen them presented more often in the context of natural language processing than programming languages.)

I don't get the impression you are thinking of one of those "typed grammar" formalisms; I more get the impression that you are using the word "grammar" in an idiosyncratic way which elides the conceptual distinction between syntax and semantics, and ignores the standard usage in which the word "grammar" is primarily associated with the former not the later.


The fact remains -- you cannot know that a Tcl program is syntactically correct without running it, can you? Because the full syntax is determined by the extensions.

Can you write a parser for Tcl in Yacc?

https://compilers.iecc.com/comparch/article/99-08-100

http://computer-programming-forum.com/57-tcl/7aaac08c64c8c61...

This is why I say Tcl doesn't have a grammar. It literally lacks one by definition. Unless something fundamental has changed.

IMO it's a terrible language which should have been left in the last century with perl4.


> The fact remains -- you cannot know that a Tcl program is syntactically correct without running it, can you? Because the full syntax is determined by the extensions.

Okay, but the same is true of Common Lisp. In Common Lisp, you can't know whether a program is syntactically correct without compiling it–and compiling it executes those parts of it declared to run at compile-time (macros, EVAL-WHEN, etc). Common Lisp supports reader macros (SET-MACRO-CHARACTER), so your program can define some entirely new language syntax and immediately start using it. I found a good example [0] someone made of using it to extend Common Lisp to support embedded JSON. You slip the json-reader.lisp file into your Common Lisp application, and then you can do stuff like this:

    ;;; example.lisp
    (in-package #:example)
    (enable-json-syntax)
    (defun example-object () {
       "someArray": [1, 2, 3],
       "someBoolean": true,
       "someNull": null,
       "nestedObject": {
          "type": "example"
       }
    })
   (disable-json-syntax)
There is no way you can tell that's valid Common Lisp without actually compiling and executing the code in the json-reader.lisp file. When the compiler gets to (enable-json-syntax), it sees that it is a macro so it executes its code at compile-time. That code then redefines the meaning of the { and [ characters to be the start of JSON objects/arrays (instead of their normal meaning in Common Lisp), and installs code telling Common Lisp how to parse JSON syntax, which is triggered when those characters are encountered in input. The example-object function shows an example of using it. Finally, (disable-json-syntax) is another macro, also executed at compile time, which undoes those changes to the Common Lisp syntax.

Common Lisp did not invent the idea of allowing a program to dynamically alter the language syntax as it was being parsed; I believe the idea was first introduced in Maclisp, and from there spread to other Lisp dialects (such as Franz Lisp and Interlisp) before finally being standardised in Common Lisp. The designers of Scheme intentionally decided to leave this feature out, but some implementations/descendants of Scheme have added it back in, such as Racket [1], Guile [2], and Chicken Scheme [3]. Other Lisp-family languages (such as Clojure or Emacs Lisp) have resisted calls to add it, despite encouragement from certain quarters.

Earlier you spoke of "Tcl's lack of a grammar up against Scheme, Lisp", but if runtime-extensible syntax is a form of "lack of a grammar", then many Lisp family languages lack grammar too.

Another language for which this is true (albeit to a significantly lesser degree), is Java. With Java, you can run arbitrary code at compile time by defining an annotation processor. The annotation processor code is run when the annotation is encountered. The annotation processor is allowed to issue compilation errors. It can also generate more source code for additional classes, which gets added to the compilation process, and your program may refer to some of those generated classes, and hence need that generated code to successfully compile–for an example see [4] from the Google AutoValue docs, where the "AutoValue_Animal" class being constructed in the create() method is dynamically generated by a processor which is triggered by the @AutoValue annotation. So, if your Java program contains annotations with an associated processor, and if you define "syntactically correct" as "compiles without any errors", then you can't know if the Java program is syntactically correct without executing arbitrary Java code.

[0] https://gist.github.com/chaitanyagupta/9324402

[1] https://docs.racket-lang.org/reference/Reader_Extension.html

[2] https://www.gnu.org/software/guile/manual/html_node/Reader-E...

[3] https://wiki.call-cc.org/man/5/Module%20(chicken%20read-synt...

[4] https://github.com/google/auto/blob/master/value/userguide/i...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: