9 ms·
Oh goodness... if only there was a way for the computer to manage all the bookkeeping of what happens after what, in a way where multiple things could run at ap
by beering 13y ago
Oh goodness... if only there was a way for the computer to manage all the bookkeeping of what happens after what, in a way where multiple things could run at approximately the same time, without the programmer having to thread "promises" or "callbacks" through every single piece of non-trivial code.
We could even give a name to these sequences of operations... maybe call them "strands"... or "filaments"...
Using libraries in Node.js seems to be a matter of 1) finding a library, 2) taking a hammer and smashing it into your existing choice of continuation-tracking mechanism. We end up with N x M different ways of using a package, depending on what style the package author chose vs what style the programmer chooses. "nodeify" is a bandage on top of a missing limb.
Do people really put up with this? Just look at how many different things were benchmarked in this article---I counted 21. How many more ways of reinventing basic programming-language design is the JS community going to come up with before we realize that the emperor has no clothes?
- macspoofing 13y ago>How many more ways of reinventing basic programming-language design is the JS community going to come up with before we realize that the emperor has no clothes? Yes, JS was a rushed language that was then left to rot for 15-odd years. Unfortunately it's the language that powers the web, runs everywhere, and (along with HTML/CSS) is the only thing that all the big guys agree on. It's getting better but it is what it is.
- thoradam 13y agoWhich reminds me, wasn't ECMAScript 6 supposed to be finalised in December[1]? 1: http://en.wikipedia.org/wiki/ECMAScript#ECMAScript_Harmony_.286th_Edition.29 http://en.wikipedia.org/wiki/ECMAScript#ECMAScript_Harmony_....
- cpeterso 13y agoThe target date for ES6 has slipped to December 2014: https://github.com/rwaldron/tc39-notes/blob/48c5d285bf8bf0c4e6e8bb0c02a7c840c01cd2ff/es6/2013-03/mar-13.md#416-current-status-of-es6 https://github.com/rwaldron/tc39-notes/blob/48c5d285bf8bf0c4...
- zaphar 13y agoYes. JS runs everywhere that a modern browser runs and powers the web's client side. Those are excellent reasons to use javascript to power your web applications client side as opposed to say Flash or ActiveX. However, those have absolutely no bearing on writing your server code in JS. The only reason to run JS on your server is so you can write the server side and client side in the same language. That's a debatable reason for running JS on your server. Node incredible scalability around IO is also provided by a host of other not rushed and left to rot languages. Erlang, Go, C++, even Java has libraries for it. When it comes to server side you can make a pretty good argument that the "emperor has no clothes".
- TylerE 13y agoHardly the only reason. Look at something like Meteor, which is running not only the same language client and server side, but there is a large overlap in the actual code as well, which makes a ton of sense to me. For instance, you can run the actual, same, validation code against a form and before the data is inserted into the DB.
- pfraze 13y agoYou're underestimating NPM and the community of modules around it. Node is well-rounded, and it's capable of handling most programming tasks. I use it to write utility scripts, which it's pretty good at. When I make a service, Express is a nice DSL-like framework. It gets lots of stuff done, so I'd say it's pretty well-clothed.
- cgag 13y agoClojure/java also have lots of libraries and tools around them, as well as proper promises (where you can block and wait if you want), channels/goroutines, futures, threads, agents, reducers, etc. Erlang / Haskell / even Go are saner languages with better concurrency stories. I guess there's something to be said for not having to learn more than one language. Probably something vulgar.
- zaphar 13y agoNo I'm really not. NPM is a good package manager. I'm sure it has good modules as well. But NPM isn't the only package manager out there. Other languages have excellent package managers too. Clojars, CPAN, Ruby Gems, even erlang has a package manager now. Those are minimum reqs for a language and community. They aren't differentiators. Aside from their absence being a negative indicator.
- ebiester 13y agoHow long? Until one of the other languages (say... clojureScript) develops a large enough ecosystem and best practices around it to allow portions of code to be shared between the client and server. Oh, that also means that this given system has to reach critical mass. Oh, and since everything's server and client side, the compilation has to be rock solid and be easy enough to understand without reverting to javascript in frustration. I miss programming in Node, for nothing else that I hate having to keep up with so many paradigms and switch between the two. I only have X amount of hours to keep up. When I move back to heavy development in a language after even a few days off, there is friction. And as someone who writes both front end and back end code, it gets frustrating. I'm not as good as I could be, given the hours in the day I have.
- JoshTriplett 13y agoThreads are quite useful, and Javascript has them. However, if what you have is a computation you have the inputs to start now and won't need the result of for a while, lazy evaluation is a far more natural representation for that than a thread. Ideally, a language ought to have one representation for lazy evaluation, not a dozen; perhaps at some point a new standard will come out that standardizes some subset of lazy evaluation that has won out. Welcome to Javascript.
- zaphar 13y agoJavascript does not have threads. There are some Javascript environments that may or may not have threads in some form. Rhino, WebWorkers. But Javascript does not have a builtin concept of threads.
- gfodor 13y agoYeah I just started working on a node project and can't help but feel like I have been transported to a time 40 years ago where my operating system didn't have a process scheduler and I have to do it all myself. I literally have to think about how asynchronous behavior works every 2 or 3 lines of code. It's sheer madness.
- nawitus 13y agoYour comment is ironic because C# implemented async in 2012. Async thinking takes a while to get used, but that doesn't mean it's more difficult than threads or mutexes and whatnot. In fact, I think it's simpler. You don't have to learn anything properly new if you already know how functions work.
- gfodor 13y agowe haven't needed complicated threading on the web server for the last 20 years, because there is a natural isolation model that works most of the time: the request. node turns this on its head and says now you will need to think about concurrency always, even if you don't have a problem that naturally warrants it. that's the issue. if i want to write a goddamn shell script I need to think about concurrency. wat? are callbacks vs mutexes vs actors vs STM the best way to handle concurrency, that's debatable. but what's not debatable is that comparing concurrent vs non-concurrent code the latter is always easier for people to write and reason about, so you should tend to want to work in environments that are non-concurrent by default and let you focus just on the parts that you need to deal with concurrency.
- nawitus 13y agoOkay, now I understand your critique. I don't think it's a very good point though: Node.js is not designed for extremely simple synchronous web servers (and neither is JavaScript).
- caoilte 13y agoThat's a generational perspective. For developers fresh out of college promises, async, continuations and so forth are the norm now.
- spion 13y agoSome of those "things" you counted are based on generators, which let you to do exactly what you want. Example: https://github.com/spion/async-compare/blob/master/examples/promises-bluebird-generator.js https://github.com/spion/async-compare/blob/master/examples/... With promises, generators are not really necessary -- especially if you add arrow function syntax into the mix. https://gist.github.com/spion/8254661 https://gist.github.com/spion/8254661 (Note: that particular method in doxbee has long since been refactored to something saner with better separation of concerns :)
- dustingetz 13y agoPromises are actually very simple - so fundamental that you can think of them as dual to function composition. By a dual to function composition i mean that you can mechanically convert async promise code to everyday synchronous function calls - including everyday exceptions. That means that literally the code can look exactly the same whether or not you are async or sync. The trick is you need either macros or monads to do this. (This is kind of the whole point of monads - you could write a piece of code by composing a few functions, and then make it asynchronous without breaking the function composition! No need to rewrite your code to use callbacks; the same code will just work.)
- gcr 13y agoIs this currently possible with NodeJS? Javascript has none of the following: - Macros - Monads - call/cc
- jonsterling 13y agoMonads are not a language feature, they are a library feature.
- gcr 13y agoOk, true. They're certainly much nicer to use if you have nice syntax for them though. :)
- dustingetz 13y agoOnly true in the most pedantic sense. For monads to work, all your code needs to be pure (in the FP sense). So if you want to do anything substantial with monads in an imperative language, you need to rewrite the entire ecosystem of libraries. That would cost quite a bit more money than your average organization can afford ;)
- jonsterling 13y agoAlso has nothing to do with the language, mate. Your argument does nothing but agree with my point :)
- davedx 13y agoYou mean like fibers? :) https://github.com/laverdet/node-fibers https://github.com/laverdet/node-fibers This is what Meteor uses on the server side, and it's a pleasure. Everything is suddenly synchronous.
- gcr 13y ago(Edit: Oops! Sorry, I see that you're already familiar with continuations, but let me explain them for those who aren't) Sometimes, fundamental switches in thinking are worth it. :) For example, continuations would be perfect here, and are a wonderful tool for simplifying "nested callback hell" type problems. But why should a web developer care about continuations? Consider Paul Graham's Arc challenge: Build a web page that presents a form to the user. After they submit the form, a new page presents them with a link. The link takes them to a third page where the submitted value is presented back to the user. The restriction is that the input field must not be passed in via the URL. Right now, the user must write in "continuation-passing style", which means threading callbacks, like this: function serve(req,res) { askUserForValue(req,res, function(value){ showLink(req, res, function(){ render(res, {"user-value": value}); }); }); } Or perhaps the user could somehow stuff the variable into a "session" library with three separate URL routes: function serve(req,res) { render the form with the POST action of /submit; } function submit(req,res, value) { req.session["uservalue"] = value; render the link that sends the user to /view; } function view(req,res) { render the value of req.session["uservaule"]; } This one is even more fragmented since you have three separate functions that model one user interaction flow! I certainly like it less than the callback example -- at least I can keep one in my head. We can do better though. Continuations let you write this: function serve(req, res) { var value = askUserForValue(); showLink(); render(res, {"user-value": value}); } If node.js supported continuations, the askUserForValue() function would respond with the form and suspend the serve function right then and there. After the user made a new HTTP call, the suspended askUserForValue() call would return to serve() and its return value would be placed into our variable. Then, the showLink() function could render the link and suspend the function again. Once the user makes another HTTP request, the function resumes, and so on. The server would have to store the state of the computation itself to disk so it could continue later. With continuations, we can pretend the user's web browser is the program counter. This frees my mind up. First, I don't have to keep callbacks in my head since there aren't any callbacks anymore. Second, stack traces work the way I expect because functions explicitly call each other. Third, if askForValue() throws an exception if the user inputs a string where I entered a number, no problem! Just wrap it in a try{} block that asks the user to enter a valid value, as if I'm writing a text program that calls readline(). Also note that this is different from just letting each user interaction be in its own thread! Consider: 1. Continuations should be serializable to disk. You wouldn't want blocked threads to just pile up as more users visit your website, and if your server crashes, you certainly wouldn't want to forget their state. 2. The browser "back" button would have to step a program backwards in time; something that is unsupported in a naïve thread-equals-user-interaction system. (E.g. how many of you have booked an airplane ticket with Travelocity/Expedia/whatever, pressed "Back", and then got a big error because the server didn't know how to step backwards through its user stack?) But the ability to save continuations to disk is the ability to save the current state of the program to disk, which makes stepping back in time easy: you can simply reload what was about to happen, just like savestates in a video game emulator. This is not a new idea. Many Common Lisp and Smalltack web frameworks work well with continuations and have done so for years (the first Seaside release was 2002, I'm not kidding you!) Racket, a great dialect of Scheme, ships with such a web framework out of the box. Here's my implementation of the Arc challenge in Racket. Note how the 'start' function is implemented: https://gist.github.com/gcr/ad116f565e105c8b2e0d https://gist.github.com/gcr/ad116f565e105c8b2e0d It's super easy to try this out and you don't need to fiddle with dependencies or anything. Just download Racket from http://racket-lang.org/ http://racket-lang.org/ , copy+paste the code into DrRacket's giant text box on the top, press Run, and your web browser will pop up with the example.
- bbllee 13y agoI find one of your premises very thin: browser implementors are implementing DOM promises, so promises were clearly not invented solely to make up for the difficulties of Node.
- SimHacker 13y agoThe emperor may have no clothes, but what's so great about clothes? (If God meant people to be naked, they'd be born that way! Same goes for programming languages.) The naked Emperor JavaScript runs everywhere, and runs fast, and isn't going away. He's streaking at lightning speed all over the kingdom, everybody's seen him, and he doesn't stay still. The emperor is naked. Long run the emperor.