44 comments

[ 3.2 ms ] story [ 26.8 ms ] thread
Was forced to learn Tcl this year after being able ignore it for the past 20 years. Hard to warm up to but not as horrible as I feared.
OTOH, I quite liked TCL. Nicely lispy, although with a few rough edges, and not a bad language on the whole.
What's so bad about Tcl?

I'd rather use Tcl than JavaScript.

That's not fair. I'd rather use COBOL than JavaScript.
As a JavaScript developer I feel the same way about Java... Unfortunately JavaScript developers are fully aware they aren't Java developers, but many Java developers don't seem to share this same realization.
It's okay, JavaScript is the new Java, complete with abuse of “patterns” and everything.
Why the JS hate? sure, === is annoying, and prototypes confuse some people, but there's plenty good about it, and it's sure as hell better than COBOL.
and it's sure as hell better than COBOL.

Why don't you like COBOL? Serious question.

shrugs

Modern COBOL, or Ancient COBOL? Most people mean ancient COBOL, which is what I was talking about. I've heard modern COBOL is quite nice.

What don't you like about Ancient COBOL?
Nothing, really. COBOL is the way it is by design. It is not something that its creators should be expected to regret to have done this way and not the other. The language was designed to serve a specific purpose, and it has served well. Look at SQL (which originally stood for "Structured-English Query language"). It shares some important features with COBOL (being "structured English", having easy-to-understand semantics), and, of course, just like COBOL, it often meets some harsh criticisms. I think that bringing both languages together (and I am not talking about Embedded SQL here) could result in a kind of "happy marriage" - in that one would get a pretty powerful tool for doing stuff on a computer without having to learn complex control and data structures - let alone things like macros, generics, iterators and such. I have met people who struggled with Visual Basic and who would certainly struggle with such languages as Python, but who have enough intuition and logical abilities to make it possible for their untrained intelligence to successfully create useful programs in COLBOL and SQL - not unlike non-programmers showing the ability to use, say, Microsoft Excel, very skillfully and efficiently (which, I must say, not every programmer can do; incidentally, I have also met professional programmers who struggled with programming subjects I'd thought were easy to understand!).
Primarily, the irritating verbosity, which still exists in modern cobol. In addition, it has many frustrating features and misfeatures, which may have made sense at the time, but definitely don't now. Modern COBOL has much of the same, but at least there are alternatives to many of the more awkward bits.
(comment deleted)
Plenty of reasons. For example, weird scoping of variables, that pretends that things are block-scoped syntactically, but they are actually not - and this is something that's extremely easy to step into with closures (which people tout as one of those great JS things). Or the whole "this" thing, again, conflicting with closures.

ES6 is a significant improvement for sure, but we aren't there yet.

In the meantime, a better question to ask, I think, is why all the JS love? What does it actually offer as a language, that others do not? The only thing that is universally acknowledged is that it's your only choice when targeting the browser, but that's not exactly a ringing endorsement. What other aspects are desirable?

(And please don't say "closures". Even C++ and Java have them these days, so it's not really an achievement - more of a baseline.)

What do I love about JS? Oh, jeez...

-idiomatic higher-order functions

-relatively small (at least, until ES6)

-"this" (I kind of have a love/hate relationship with it, really)

-very little odd about the syntax (for a C-like language, everything is pretty much what you expect it to be, save some of the OO stuff, and the obvious elephant in the room that is ==).

-prototypical inheritance

-really easy serialization

-builtin regex support

-first-class functions that are equivalent to lambdas (you'd be surprised how many languages don't have this: It's pretty much just JS in the mainstream language space, AFAIK)

-A vibrant community, that, while not always exactly on target, is always doing somthing new and interesting, and constantly iterating on ideas.

-As of ES7, TCO.

Don't get me wrong, there's plenty wrong with JS: I'd say more than is wrong with Python, and less than is wrong with Perl, and there are some quite nasty pitfalls, but it's not a horrible language by any stretch, and certainly not deserving of its reputation as a hacky, bastardized byproduct of Brendan Eich's sleep-deprived brain.

Now if you want to see a REALLY stomach-churning scripting language, have a look at QuakeC. Carmack, I stand in awe of your brilliance, and I understand the necessity of hyper-optimization at the time, but are you sure you didn't contact some horrifying elder god to write this for you?

>> idiomatic higher-order functions

Mmm... I wouldn't really say that JS is a good example of idiomatic HOF - just look at the standard library. I would say that JS has specific idiomatic patterns (such as callbacks) that are a subset of HOF, but most JS code you see around is not like ML or Haskell with regard to HOF in general.

>> very little odd about the syntax (for a C-like language, everything is pretty much what you expect it to be, save some of the OO stuff, and the obvious elephant in the room that is ==).

And scoping. And magic semicolons.

>> first-class functions that are equivalent to lambdas (you'd be surprised how many languages don't have this: It's pretty much just JS in the mainstream language space, AFAIK)

Can you clarify? So far as I can see, all you need for lambdas are first-class functions (function-typed values), function literals, and closure semantics for the latter. Most mainstream languages offer that these days. C# would be a good example - what do you find limiting about its lambdas that JS does better?

>> Now if you want to see a REALLY stomach-churning scripting language, have a look at QuakeC.

QuakeC was basically just C with only primitive data types (no pointers or arrays!), and a single reference type that referenced a single struct type with an extensible definition. So yeah, not very impressive; but it mostly did what it needed to do in its niche.

Besides, it was fun fighting with the language limitations sometimes (e.g. you could simulate a global array by writing a function with a giant conditional inside - or, better yet, writing a code generator to do it for you). Again, not something you really want in a "production" language - but as far as writing game mods went, fun was usually the primary goal for most who did it.

(comment deleted)
>Mmm... I wouldn't really say that JS is a good example of idiomatic HOF - just look at the standard library. I would say that JS has specific idiomatic patterns (such as callbacks) that are a subset of HOF, but most JS code you see around is not like ML or Haskell with regard to HOF in general.

Lodash/Underscore is tremendously popular. Yes, most JS libs HOF merely for callbacks, but the IDEA of, "foo takes a function and returns a function," is a fairly widespread idea in the JS community: The same is true of ruby, and a few other mainstream languages.

>And scoping. And magic semicolons.

Scoping is semantics, not syntax. And yeah, scoping semantics suck. But hey, IIRC at least they were never as bad as python's used to be :-).

However, this is no excuse for how awful the semantics are. Variable Hoisting is the devil. However, ES6 seems to improve this somewhat.

As for the 'magic semicolons,' JS doesn't do ASI when the syntax is ambiguous. So I fail to see what's so magical about them.

Unless you mean the semicolon/lack of semicolon on the end of a function definition. And that's for the same reason as C struct semicolons, and about as easy to remember.

>Can you clarify? So far as I can see, all you need for lambdas are first-class functions (function-typed values), function literals, and closure semantics for the latter. Most mainstream languages offer that these days. C# would be a good example - what do you find limiting about its lambdas that JS does better?

<rant>

First of all, people talk closures like they're some magical entity: They're not. They are a natural consequence of lexical scoping and every lexically scoped language you have ever used has them. Yes, even whatever one you're thinking of right now. They may not support inner functions, but all a closure is is a lexically closed environment, so semantically, EVERY function is a closure.

</rant>

My pedantic nature over that aside, yes, I will gladly clarify. I am not familiar with C# or Perl, and am not super familiar with the Java lambda semantics, so let's talk scripting languages: Ruby, Python, JS. And since this IS JS's domain, and Perl is Perl, the comparison should be useful.

Let's start with Python:

  def apply(f, arglis):
      f(*arglis)
It seems simple enough, but as you no doubt know, Python's lambdas can only have one statement: So while this works:

  >>>apply((lambda x, y: x+y), 1, 2)
  =>3
This doesn't:

  >>>apply((lambda x: \
  ...    if x:
  ...        print("oh noes")), 2)
  =>syntax error
Next, ruby. Off the bat, Ruby looks better: blocks, procs, and lambdas are everywhere!

And thus begins our first problem: Blocks, Procs, and Lambdas are all SUBTLEY DIFFERENT. Bad, okay, but not awful.

However, Ruby is, unlike Python, fully Object Oriented. Thus, procs and lambdas are instances of their respective classes. What ruby should have done is introduce python style call methods, allowing any object to act like a function. Instead, much like Smalltalk before it, it added a call method to each object, which you call to invoke the code. This means that you can't just pass in a kernel method (What most of us call functions) instead of a block or proc when a function is expecting one: you have to wrap it. Thus, functions defined with def aren't the same as the anonymous procs you create: they're different entities. The Schemer in me is shouting that making functions and lambdas different entities should be a compiler optimization, not something transparent to the programmer.

Finally, Java: I said I wouldn't cover this, I lied. Java actually handles lambdas surprisingly well. The only problem is that a lambda can only touch 'final' variables. So a lambda can read the args of the function that created it, but it can't change them, and thus you cannot g...

>> the IDEA of, "foo takes a function and returns a function," is a fairly widespread idea in the JS community: The same is true of ruby, and a few other mainstream languages.

I would say that it's getting mainstream in general. I'm working on an ASP.NET Core application as I'm writing this comment, and you'd be surprised as to how many functions get passed around and returned routinely. I was surprised myself.

>> Scoping is semantics, not syntax.

It is, but semantics is supposed to correlate with syntax in a sane way. In JS, it does not - you can place "var" inside a block, but it's not actually scoped to that block. If they required all vars to be declared at the beginning of the function, it would have made more sense. And I'm not aware of any other language that made the same blunder, except for old (pre-.NET) Visual Basic.

Python scoping is comparatively sane in comparison in a sense that the rules follow the syntax. You still can't scope to a block, but you're not misled to believe that you could.

>> As for the 'magic semicolons,' JS doesn't do ASI when the syntax is ambiguous

return

42

>> all a closure is is a lexically closed environment, so semantically, EVERY function is a closure.

True, but in common use, we usually mean "closures that can close over something other than the global environment". The other kind is just too trivial to be worth discussing on its own.

Regarding lambda semantics, I'll grant you that Python doesn't have full-fledged lambdas in that sense. But then again, they argue that if you need a multiline closure, it should have a name for readability purposes - I don't necessarily agree, but it's not an obviously invalid argument. And as far as expressiveness goes, named local functions provide the same degree of it, even if the code is more verbose.

On Ruby, I think the distinction between blocks, procs and lambdas is necessary if you want to provide various gradations of what "capture the lexical scope" means - and in particular, how you want to treat the meaning of "return", "break" and similar statements that, effectively, have an implicit jump target. In some circumstances, you may want to capture the target from the outer scope; in others, you do not. Still, they could have made do with two different types of closures, rather than three, one of which isn't even first-class.

FWIW, in C#, lambdas behave quite a bit like Java ones, except 1) they can mutate locals (which are automatically hoisted to the heap in that case), and 2) instead of implicitly implementing interfaces, the language provides function types (delegates), and a lambda automatically creates an instance of a delegate when used in the appropriate context. So you can directly pass functions to other functions etc.

(I oversimplify somewhat, because C# delegates are actually multicast, so they're not quite a bare-bones function type - but 99% of the time all those extras are unused.)

Then we have C++, where lambdas are also just objects with operator() defined for them, and no specific type otherwise (you have std::function when you need such a type, but idiomatic C++ is to use templates, so that lambdas can be inlined as much as possible).

So we can add C# and Lua to the list of languages that have good lambda support.

I forgot lua before. Lua is pretty much javascript except without all the screwups and with 1-indexed arrays.

>It is, but semantics is supposed to correlate with syntax in a sane way. In JS, it does not - you can place "var" inside a block, but it's not actually scoped to that block. If they required all vars to be declared at the beginning of the function, it would have made more sense. And I'm not aware of any other language that made the same blunder, except for old (pre-.NET) Visual Basic.

Ah. Yeah. Well, that's why let exists now.

>return

>42

All right, I'll give you that.

Mind sharing what you are using it for?
It's the embedded scripting language in some of our printers so we use it during development of new products.
I believe Tcl is still used to script some major EDA tools, or at least in the well-antiquated versions of the tools my university was using.
EDA = Electronic Design Automation (probably)
It is used in the semiconductor industry that I'm now part of. But it's actually pretty nice. Doesn't come as easily as Ruby does to me, still pretty handy
Definitely an improvement over the hacked-together messy collection of languages that it replaced. I like tcl.
I am making $340 to $350 per hour by online working on facebook. i was jobless a year ago , but now i am getting my own salary by doing this online job. This salary is enough for me to meet my expences. I am really thankful to God. If you want to make this salary like my , you can check my details.⤵

CLICK THIS LINKHERE HERE===>>>>>>> w­­w­­w.W­­a­­g­­e­­N­­e­­T­­9.ℂ­­o­­m

Don Libes' Exploring Expect[1] is a devops classic (if there is such a thing). Highly recommended for those wondering what Tcl is (still) good for! It would be nice if O'Reilly would make the text (completely) freely accessible[2], as they have done with some their other older titles[3].

See also the Caius framework[4].

[1] http://shop.oreilly.com/product/9781565920903.do

[&] http://www.nist.gov/el/msid/expect.cfm

[2] https://www.safaribooksonline.com/library/view/exploring-exp...

[3] http://www.oreilly.com/openbook/

[4] http://caiusproject.com/

Oh wow, I've written probably over 50 thousand of lines of Tcl from 2000 - 2009. Started out automating SNMP testing, and then the entire suite of WiFi Alliance certification tests. Blast from the past.
Tcl shares a little with the lisp family.

Not just being mostly homoiconic, but also the feelings one gets when learning it.

I went from "this syntax is a mess" in my junior developer days to "aha! it is so powerful" once I grokked it, for both languages.

Few other languages really gave me that stark contrast in perspective once I had that moment.

That's because most languages have roughly equivalent / familiar syntax, thus you don't start out saying "this syntax is a mess" to begin with.
You also don't get the aha! moment either. At least, not in most mainstream languages.
With regard to Lisp, I went from "finally, a syntax that is incredibly clean and well-designed" to "aha! it is so powerful".
How easily can Tk be completely separated from Tcl?

I've been taking an admittedly superficial look at this landscape; it seems that languages which have Tk bindings rely on the entire Tck/Tk package, and tend to have some Tcl cruft in them.

A lot of Tk is written in Tcl, so it is probably easier to write another toolkit rather than separate them.
I see; so what you're saying Tk bindings actually invoke Tcl execution, in addition to the lower level C API (functions named Tk_Whatever); i.e. there is no Tk without Tcl being interpreted.
Yes this is correct. I looked into doing this to see if it was possible to use Tk with the Jim interpreter. It's probably possible but would be a significant investment of time. Tk has some deep integration into Tcl internals.
Yes, interestingly Tk is the perfect Trojan horse. It is the simplest, most useful platform-independent toolkit ever written. But that simplicity is derived from its integration with Tcl, so Tcl needs to be installed everywhere Tk runs.
A lot of libraries implement Tk, so you can pretty much write Tk in ruby, python, perl, etc.

The following link includes example in pure Tk, Python, Ruby & Perl. http://www.tkdocs.com/tutorial/firstexample.html

They do this by bundling A Tcl interpreter with the exception of PerlTk (not to be confused with Tcl::Tk extension)
I don't know why, but every time I see Tcl popup on HN or somewhere else, I get this nostalgic feeling of writing tcl scripts for IRC eggdrop bots in the early 2000s.

For those that remember, this site has a good collection of such scripts: http://www.egghelp.org/tcl.htm

I miss the days when IRC was the primary way of messaging people. Thinking back of quakenet and gamesurge... Nothing has really managed to replace that community infrastructure IRC provided. Especially for PC gamers.

Even joining your local city's channel, to find folks with common interests, and instantly chat with them. Ahhh, the feels!

I wasn't a gamer, but belonging to ECHO (East Coast Hang Out) in NYC in the early 90s was similar. We had monthly meetups at a bar downtown, and I got to meet people with similar and different, but interesting passions.

I chalk it up to the novelty and size of this sort of thing back then. It exists now in meetups and other such things like Gitter, but it's more common, so it seems less special (but it's not!).

I still use it for small, quick apps with a GUI. Like most older languages, there are a lot of gems that have been written that you can study.