6 ms·
Not just first class functions -- anonymous functions, and closures. Python has first class functions, but not anonymous functions, since lambdas aren't full f
by chubot 12y ago
Not just first class functions -- anonymous functions, and closures.
Python has first class functions, but not anonymous functions, since lambdas aren't full functions.
And Python doesn't have closures, because you have to use "global" or "nonlocal" (in Python 3) to assign a a variable in an enclosing scope.
These features let you write concurrent state machines in JS without explicit state -- you basically use the stack as state.
Python was pretty early in terms of event loop programming for interpreted languages -- asyncore in the stdlib, and Twisted. But I agree that the node.js style is nicer than asyncore, Twisted, or Tornado. I prefer coroutines over state machines, but if you're going to write state machines, than doing it with anonymous closures is nicer than doing it "manually" with classes and so forth.
Tcl was even earlier, but Tcl is pretty foreign to most people, and was more of an embedded language than a scripting language. Pretty sure Tcl has full anonymous closures, but it is a bizarre language in some other ways.
I haven't seen the event loop style in Perl but I think you can do it. If someone has an example I'd like to see it. To me, Perl only barely qualified as a real programming language because you can't even name your function params? At least when I used it, which was over 10 years ago.
- pdpi 12y agoOn the other end of the spectrum, Ruby blocks (and all the attached machinery) feel to me like a much nicer abstraction to work with. Go's goroutines and channels show giving a language purpose-built concurrency primitives is a really nice model (I expect Erlang would be another good example of the same, but never tried it), and the monadic approach in Haskell makes it so that you could almost directly translate node.js code and end up with something far more readable.
- ufo 12y agoTBH Python is a bit of an exception there. Most languages with first-class functions (specially more modern ones) will also come with anonymous functions that aren't intentionally crippled (like Python's lambda is) and will have more traditional lexical scoping instead of local-by-default.
- chubot 12y agoWhich ones? Python isn't an exception among languages that people in industry actually use. For "production grade" server software, which is driving the newfound interest in concurrency, the following languages cover 99% of code written in the last 20 years: C/C++/Java/PHP/Perl/Python/Ruby and the Microsoft Stack (C#, VB). None of them have anonymous closures. (C# might, but it's also newer, and it's not the the prevailing style of concurrency in any case.) This is basically JavaScript's Scheme heritage showing through. Anonymous closures are old hat for people who went through a CS program teaching Lisp, but they're not by any means standard in industry. One of the main reasons that none of the languages needed this feature is because the predominant paradigm for concurrency for the last 2 decades was threading, not state machines and callbacks.
- nawariata 12y agoPHP has closures.
- TazeTSchnitzel 12y agoPseudo-closures. They capture variables by value, though you can use PHP's referencing mechanism to have something sort of closure-like.
- afjgasdfjlasdf 12y agoThere is no such thing as an "anonymous closure". There are only anonymous functions which may or may not create a closure. Early LISPs either had no way of creating closures, or did so through some sort of function or other mechanism. It wasn't until Scheme came around that lexical closures really became a thing in Lisp world. Perl and PHP both have closures. In fact, Perl is closer to Scheme/Lisp than most languages (at least Perl doesn't screw up scoping like JavaScript, replace first-class functions with second-class-bastardizations like Ruby, or do whatever Python thinks it's doing with lambda... ugh)
- chubot 12y ago
- barosl 12y ago> I prefer coroutines over state machines And that's why Python supports `asyncio` (not to be confused with `asyncore` which is obsolete). So I prefer: sock = yield from connect('localhost', 7942) msg = yield from read_message(sock) print(msg) to this callback hell: connect('localhost', 7942, function(sock) { read_message(sock, function(msg)) { console.log(msg); }); }); And they're completely equivalent. Why would someone actually like the latter, except you're forced to use it because of the prevalence of JavaScript? `asyncio` is not only easier to use than the traditional "manual" state machines with classes, but also much faster than something like `Twisted`. In my crappy local benchmark[1], it easily beat `Twisted` in a considerable margin. That may be because of the flaws in my test code, but still their performance is on par. I see no points in relying on callback hell, at least in Python, except the lack of the libraries that support asyncio, which makes me a little bit sad. [1] https://github.com/barosl/ws-bench https://github.com/barosl/ws-bench
- chubot 12y agoYeah but node.js predates asyncio by about 5 years. Python was early to the game with asyncore and Twisted (circa early 2000's), but the async I/O support stagnated and left a big hole for node.js. Part of the reason for stagnation was because you really need new language features -- i.e. yield/send, yield from, etc. JavaScript already had the necessary language features for its concurrency model.
- barosl 12y agoThat's a good point. I also think `asyncio` was way too late in the game. I just wanted to mention the feature that was missed from your comment, which I think is not fair to Python.
- timepiece 12y agoCan't you use promises/deferreds instead?
- barosl 12y agoI do think promise and deferred are huge improvements to ergonomics, but still... I cannot completely love the code bloat (which is much smaller and easier to reason about than callback hell, of course) that is caused by those libraries. I much prefer Haskell's monadic interface or Python's `yield from`. But that may be my personal preference.