10 ms·
Kal – a clean JavaScript alternative without callbacks
- rzimmerman 13y agoThis is a project I've been working on in my spare time for a while now and I've finally decided to throw it out there and get some feedback. Do you think the 'wait for' callback syntax is useful? What big features do you think are missing?
- msoad 13y agoLooks pretty good! I like it. To be honest I will not use it in my projects. I prefer using ES6 syntax for this problem when it's available.
- optymizer 13y agowhat's the (equivalent?) ES6 syntax? I'm genuinely curious.
- ricardobeat 13y agoThe async handlers looks great, specially parallel and series iterators. I'm not sold on wait for friends from db.friends.find() //vs friends = await db.friends.find() it's a bit hard to follow despite the natural language. Is this a fork of the CoffeeScript compiler? Will it benefit from upstream changes/features?
- rzimmerman 13y agoIt's not a fork of CoffeeScript (though there are a lot of similarities). I'd initially tried doing that but I really couldn't get things to work the way I wanted. Mostly, it's a pretty major rearchitecture to get coffee to parse a function block that way. I think syntax highlighting helps a lot in this case, so try out the tmbundle in Sublime or TextMate (https://github.com/rzimmerman/kal.tmbundle https://github.com/rzimmerman/kal.tmbundle) if you can.
- graue 13y agoI also vote for 'await' here. The 'wait for friends from' construct looks too much like BASIC for my liking. It's not clear which terms are built into the language ('wait', 'for', 'from') and which are not ('friends'). Also, since the eventual result of that line is an assignment to 'friends', using the existing = operator makes the language more consistent.
- rzimmerman 13y agoThanks for the feedback. It seems like a lot of people would prefer a more normal looking assignment. If you get a chance (and use TextMate or Sublime Text), please give syntax highlighting a try (https://github.com/rzimmerman/kal.tmbundle https://github.com/rzimmerman/kal.tmbundle)!
- graue 13y agoUnfortunately I don't use those editors — maybe you can write a Vim highlighter next? Might also be worth adding syntax highlighting to the website (even if you have to do it manually for now), if you're set on the current syntax and think highlighting will make that much of a difference.
- jasonlotito 13y agoHave you tried converting it in: http://coloration.ku1ik.com http://coloration.ku1ik.com
- wooter 13y agoAlthough I cannot agree more with you and csheid, you really should give sublimetext a try. I've been quite impressed.
- cscheid 13y agoIt's more than assignments looking normal. "await x" is better since it's an expression and not a statement. That is, "await x" will be a placeholder for a value (after the appropriate CPS, of course), while the assignment syntax forces you to use a temporary variable, even if you don't need it.
- WayneDB 13y agoThis is a fantastic spare time project. At the very least, it will be a beautiful feather in your cap :)
- skybrian 13y agoI'd be more interested in performance than features. If you use tasks when they're not needed, how much more JavaScript code does it take and how fast does it run? Also, what do stack traces look like?
- ilaksh 13y agoAre you aware of the ToffeeScript project? Can you make them a website and start promoting it? Because you are missing all if the features in ToffeeScript/CoffeeScripy and ToffesScript needs a shiny website because that's how people judge languages now is how shiny their website is apparently based on the fact that no one seems to care about ToffeeScript. BTW no I'm not the author of ToffeeScript.
- tuxracer 13y agohttps://github.com/kriskowal/q https://github.com/kriskowal/q solves this today without needing to cross compile. http://koush.com/post/yield-await-v8 http://koush.com/post/yield-await-v8 will address this natively however unlike Q or Kal you can't start using it today.
- ricardobeat 13y agoThere is no need for hacks, just run node with the `--harmony` flag to get yield support today. Q is a huge, monster library. It's 2x the size of caolan/async, which is already bloated. I personally think it's better to use https://github.com/mbostock/queue https://github.com/mbostock/queue or another small, understandable library.
- graue 13y agoRespectfully, is it possible you've confused Q with something else? I compressed and minified both caolan/async and kriskowal/q. Result: async is 3.4 KB, q is 4.1 KB. I grant you that mbostock's queue is even smaller, but all are so tiny as to be a trivial download even on mobile. The important issue here is IMHO not the size of the libraries, but how much they help you write maintainable code.
- ChiperSoft 13y agoIf you're taking about node, what difference does it make how large the library is?
- ricardobeat 13y agoThese libraries work in the browser. It's not just size: debugging, understanding code, and performance matter too.
- rzimmerman 13y agoQ and ECMAScript 6 solve the callback issue, but I think people might like the built in async iterators and error handling.
- 10098 13y agoThe title is kinda funny to the russian ear because kal means feces in Russian :)
- rzimmerman 13y agoThat is really unfortunate... I chose it because it in Hebrew it roughly means something like easy/simple/BASIC. edit: More importantly, does that make you more or less likely to use it?
- raquo 13y agoI'm Russian and I didn't blink reading the title. I never stopped to contemplate the fece-ness of iCal either, until today (thank you, 10098). Anyway, keep the name. It's a fun easter egg as far as I'm concerned. Also, note that kal is mere `faeces` in Russian, not `shit`. I don't remember when I've last used the word outside of a hospital... or inside, for that matter.
- 10098 13y agoActually, doesn't affect the likelihood of me using it :)
- aquadrop 13y agoIt's kinda fun and doesn't affect chances that I'll be using it, but I'd imagine it would be funny when someone will try to convince boss to use Kal :)
- ludwigvan 13y ago`kal` means `stay` in Turkish, quite fittingly :)
- pjmlp 13y agoWell, even worse is the Portuguese name Rui. I was once told it also sounds like something bad in Russian, so it can be a bit inconvenient introducing anyone with such name in Russian if not aware of this issue.
- u2328 13y agoYay, another JavaScript super-set language that solves one problem.
- omni 13y agoAssuming CoffeeScript is in your list of JS super-set languages, what do you consider to be the one problem it solves?
- deleted 13y ago[deleted]
- rzimmerman 13y agoPsh, this solves at least two issues. Don't forget the Boolean "but" operator...
- esmevane 13y agoWhat's with this attitude? This is someone's personal project.
- u2328 13y agoYou're right. I apologize for my remark. It was crass and uncalled for.
- ra88it 13y agoYeah, this shit's bogus man. It only solves one problem.
- graue 13y agoOn the one hand, this comment has the kernel of a legitimate criticism in it, and gets across why I probably won't use this language in a real project. On the other hand, that's so rude! Not every project has to be the next CoffeeScript to be interesting and worthy of appreciation. If you don't like it, just click on a different story instead of cutting down someone who chose to make something cool and share it with us.
- pencilcode 13y agoi really like the syntax - really close to english. is there a side-by-side comparison of kal and the generated javascript?
- rzimmerman 13y agoThanks for the suggestion. The closest to a side by side is here (http://rzimmerman.github.io/kal/#asynchronous-wait http://rzimmerman.github.io/kal/#asynchronous-wait), and also the table of operators in the readme (https://github.com/rzimmerman/kal/blob/master/README.md#operators-and-constants https://github.com/rzimmerman/kal/blob/master/README.md#oper...). Also the examples directory on the github repo. Apologies if you saw these already. I'll add something like what you suggested, though.
- molf 13y agoExcellent work. Especially useful since it appears to throw exceptions. That means it's a step up from Iced Coffeescript. The syntax is a little verbose and might be shortened to something like C#: `user = await db.users.findOne {name:userName}`. Would be a lot more clear to me.
- rzimmerman 13y agoDefinitely play with the exception handling. Latent bugs aside, asynchronous statements (wait fors) work in any crazy horrible nested combination of ifs, fors (parallel or series), and trys that you can think of. Take a look at the JS output with: kal -o output.js -f beautify input.kal to see the sausages being made. The http server demo is a good example (https://github.com/rzimmerman/kal/blob/master/examples/async-http-server.kal https://github.com/rzimmerman/kal/blob/master/examples/async...)
- tlb 13y agoA side-by-side line-by-line interactive display would be wonderful in writing Kal. Reading the JS explains what it's doing quite well, except that the Kal compiler uses way too many compound comma-separated statements instead of semicolons.
- rzimmerman 13y agoThat's actually a side effect of uglify.js's beautify, I believe. I'm going to try to get rid of that in upcoming releases.
- crazygringo 13y agoAs far as I can tell from reading the readme, it does NOT support throwing exceptions from within callbacks. Because, of course, there's no way to technically do that in anything that is JavaScript at its core -- at least as far as I'm aware of. Correct me if I'm wrong? It says "This includes error handling via callbacks." -- not error handling via exceptions. Elsewhere it says "Any errors reported by fs.readFile (returned via callback) will be thrown automatically.", so maybe it converts certain callback error functions to exceptions? But in any case, that's not the same as throwing an exception inside of a callback, and having it "bubble up". Unless I'm misunderstanding (which would be great!).
- calvintennant 13y agoIn the `Asynchronous Wait` example did you mean: `function getUserFriends(userName, next) {` when you wrote: `var getUserFriends(userName, next) {`?
- rzimmerman 13y agoWoops good catch!
- jay_kyburz 13y agorzimmerman I like it! and would consider using it for my next big project. If I were you I would make a slight course correction follow in the footsteps of Python and Go and have one and only one correct way to do something. When you say use two spaces, but you can use more if you want, make it an error to use more. Pick the correct way to call a function. Pick the correct way to declare a function. Keep up the good work.
- rzimmerman 13y agoThanks! I wouldn't call it stable or production ready by any means, just as a disclaimer.
- jay_kyburz 13y agoOh hey, another idea, if you keep the project really tight and small, I wont be too intimidated to get into it and help fix issues if I start using it.
- TheZenPsycho 13y agoSo instead of encouraging you to actually fix the bad nested callback code, you can dress it over with fancy syntax. Well done on making a whole language though. It's pretty challenging and I hope you do well. Aside: This seems very similar to narrativeJS in concept http://www.neilmix.com/narrativejs/doc/ http://www.neilmix.com/narrativejs/doc/
- rzimmerman 13y agoThanks. I think the main issue with JS callback syntax is that it quickly becomes unmaintainable. Hopefully this fixes a lot of that by abstracting away the mechanics. I don't think there's something fundamentally wrong with the "relinquish control and wait for I/O" model, so I tried to make that explicit here.
- deleted 13y ago[deleted]
- mbrock 13y agoWhat do you mean by "actually fix?"
- TheZenPsycho 13y agoStop nesting anonymous functions. Un-nest them, name them, and encapsulate the process in a monad.
- TheZenPsycho 13y agomonad* *jQuery or promises like API object, whereupon you place methods- some of which may be asynchronous. an asynchronous operation returns an object with a method that performs the next action and optionally takes a callback, passing in the results of the previous asynchronous operation as a value- thus flattening the callbacks out into a sequence instead of a nesting. Constructed properly, you can create monad combinators/transformers, to do things like automatically wrap every step in your chain with exception handling. Using common JS promises libraries gives you error handling for free.
- dimadima 13y agoDoes the first example contain a syntax error?
- LordHumungous 13y agoJS without callbacks... so JS without the best part of JS?
- rzimmerman 13y agoIt's admittedly a bit link-baity. The async structures in Kal do compile to callbacks in JS.
- ufo 13y agoDont confuse closures with callbacks. Asynchronous non blocking code is the nice thing and callbacks are the price you have to pay to use that in JS,
- gnaritas 13y agoHow exactly are callbacks the best part of JS? Callback aren't a language feature, they're a pattern of doing async code with anonymous functions. Anonymous functions are used for far more than just async code and cannot be replaced with an await keyword which only replaces the need to use callback for async code.
- huu 13y agoIs it possible to cut out some of the explanatory comments in the examples or to consolidate them somehow? It's difficult to see at a glance how the code looks, especially without any syntax highlighting at this stage
- rzimmerman 13y agoI added syntax highlighting to the github landing page manually for now. Try the .tmbundle if your editor supports it. It's not full featured but it gets the colors going. I'm working on getting it into pygments.
- rybosome 13y agoIt's remarkable how similar this code looks to the monadic way of doing it. For this Kal code... task getUserFriends(userName) wait for user from db.users.findOne {name:userName} wait for friends from db.friends.find {userId:user.id} if user.type is 'power user' for parallel friend in friends wait for friendsOfFriend from db.friends.find friend for newFriend in friendsOfFriend friends.push newFriend unless newFriend in friends return friends Here's a pseudo-ish implementation in pseudo-ish Haskell. getUserFriends userName = do user <- findUser userName friends <- findFriends user if (User.type user) == "power user" then friends ++ parMap rdeepseq $ (getSecondNodes friends) friends else friends getSecondNodes firstNodes friend = do secondNodes <- findFriends friend diff firstNodes secondNodes I like the concept of Kal, and I look forward to seeing what people do with it. Regarding syntax, I have to admit that I share the opinions of a few others in terms of preferring symbols over so many keywords, but that's a minor nitpick. Great job!
- rzimmerman 13y agoThanks! I had not thought to make the comparison to Haskell and monads. That's pretty interesting. A lot of people prefer symbols over keywords, and I think that's mainly a readability issue. I personally prefer more keywords with good syntax highlighting, so that's what I went with (and why I almost immediately made a .tmbundle).
- iandanforth 13y agoComing from a Python background I appreciate the verbosity. There are times when symbols and being concise may be necessary, but I find a non-expert human readable default to be very appealing. Thanks for your hard work!
- pcj 13y agoThis is beautiful work! I see small shades of inspiration from the .Net TPL[1] and the more recent async-await paradigm[2] in C#. But, this is way more concise and beautiful implementation :-) [1] - http://msdn.microsoft.com/en-us/library/vstudio/system.threading.tasks.task.aspx http://msdn.microsoft.com/en-us/library/vstudio/system.threa... [2] - http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx http://msdn.microsoft.com/en-us/library/vstudio/hh191443.asp... and http://msdn.microsoft.com/en-us/library/vstudio/hh156528.aspx http://msdn.microsoft.com/en-us/library/vstudio/hh156528.asp...
- __xtrimsky 13y agoI Love callbacks, wtf is wrong with you guys :'(
- progx 13y agoNot callbacks are a problem, but many nested callbacks are unreadable und hard to maintain.
- tlb 13y agoI'm puzzled by the bootstrapping process. It's written in Kal itself, and you distributed compiled code as JS. Do you have a way of re-boostrapping from only the source in github?
- rzimmerman 13y agoThe only way to re-bootstrap is to download a compiled (JS) release from npm, then use that to compile the .kal source in the git repository. Then you can use your newly compiled version of kal to recompile itself. This is how I create the npm releases. It's not turtles all the way down, though. If you look way back, the 0.1ish releases of the compiler were written in CoffeeScript. I ported the compiler source over from CoffeeScript file by file as it matured and eventually got rid of the dependency entirely. Technically, you could start with the last release that was written in CoffeeScript and compile up to the current release.
- tlb 13y agoInteresting. It must get tricky when you make an incompatible change to the language. I guess you'd make the changes to the compiler still using the old language, update the test cases, make it stable, then change the compiler sources to reflect the new language, recompile the compiler, then check in the new compiler JS. With plenty of git checkpoints along the way.
- arnarbi 13y agoOne of the gems in CS literature illustrates this nicely: http://cm.bell-labs.com/who/ken/trust.html http://cm.bell-labs.com/who/ken/trust.html Essentially self-compiling compilers can "remember" things that are nowhere to be found in the source code.
- ufo 13y agoDoes anyone know if there is a JS dialect out there that adds support for callback-less async code without also adding a bunch of other coffeescripty syntax changes at the same time?
- simonster 13y agoThat would be TameJS: https://github.com/maxtaco/tamejs https://github.com/maxtaco/tamejs
- neilk 13y agoYes, it's called "JavaScript". Specifically, combining generators with promises. http://blog.alexmaccaw.com/how-yield-will-transform-node http://blog.alexmaccaw.com/how-yield-will-transform-node Definitely not as clean as a whole new language, but you can program like this today, at least in bleeding edge node and some recent browsers.
- mjw 13y agoTry http://www.neilmix.com/narrativejs/doc/ http://www.neilmix.com/narrativejs/doc/ -- "a small extension to the JavaScript language that enables blocking capabilities for asynchronous event callbacks".
- gfxmonk 13y agoStratifiedJS allows you to write callback-less async code, including full support for exceptions thrown from async code (stacktraces and all): http://onilabs.com/stratifiedjs http://onilabs.com/stratifiedjs (disclosure: I work at Oni Labs) It does extend JS with some additional syntax as well (new concurrency constructs as well as some syntactic sugar), but it doesn't alter existing JS syntax.
- mjackson 13y agoFor the curious, the equivalent example from the OP using promises[1]: function getUserFriends(userName) { return db.users.findOne({ name: userName }).then(function (user) { return db.friends.find({ userId: user.id }); }); } [1]: http://promises-aplus.github.io/promises-spec/ http://promises-aplus.github.io/promises-spec/
- prezjordan 13y agoIt's more obvious if you have multiple levels. function getUserFriends(userName) { return db.users.findOne({ name: userName }) .then(function (user) { return db.friends.find({ userId: user.id }); }) .then(function (friends) { return somethingAsync(friends); }); }
- mjackson 13y agoI don't ever write code like this personally. The multiple levels make it more difficult to reason about, IMO.
- rzimmerman 13y agoThanks for the comparison, I should probably add promise syntax to the landing page to cover more bases. I think a useful case would be the trickier stuff where Kal really shines. For example, doing async stuff inside of loops, conditional calls (where some paths need async waits and others don't) and error handling. I also think the Kal syntax might appeal to people who are less experienced with JavaScript and it's more eclectic features.
- tlrobinson 13y agoPromises + CoffeeScript really hits the sweet spot for me: getUserFriends = (userName) -> db.users.findOne(name: userName).then (user) -> db.friends.find userId: user.id Or prezjordan's example: getUserFriends = (userName) -> db.users.findOne(name: userName) .then (user) -> db.friends.find userId: user.id .then(function (friends) -> somethingAsync(friends) The concise function syntax and implicit "return" really helps. If that's not good enough you can implement higher level control flow abstractions much more nicely than with raw callbacks, e.x. https://github.com/tlrobinson/q-step https://github.com/tlrobinson/q-step getUserFriends = (userName) -> QStep( -> db.users.findOne name: userName (user) -> db.friends.find userId: user.id (friends) -> somethingAsync friends )
- ilaksh 13y agoToffeeScript is very similar but better.https://github.com/jiangmiao/toffee-script https://github.com/jiangmiao/toffee-script
- aaronharder 13y agoOK. Better how?
- ghotli 13y agoThis comment would be much more insightful if you put forth your argument as to why it is better.
- ilaksh 13y agoSorry I was in a hurry. It has many more features for a sync that looks like sync and for other things. It has a cleaner syntax. It supports easy access to multiple callback return values. It has all of the other CoffeeScript features. It seems very obvious if you look at ToffeeScript that it is objectively better. I find it difficult to believe that it isn't getting more attention. Probably just because it doesn't have a web site.
- a__remie 13y agocbs - cbSucces cbe - cbError replaces all the "if (e) return cb(e)" lines with cbe when you call the async function. A whole abstraction over js just because of this, running away from the problem...instead of solving it on the spot, keep running.
- halacsy 13y agovery cool & pragmatic project: javascript / java / c++ coders get one step closer to functional programming.
- arghbleargh 13y agoIt appears to be very similar to icedcoffeescript: http://maxtaco.github.io/coffee-script/ http://maxtaco.github.io/coffee-script/
- anuragramdasan 13y agoOf the tonnes of Javascript libraries that are unloaded on HN regularly, this is one of the more fascinating ones. Absolutely love the syntax. Great job!
- kev6168 13y agoI suggest to use ..= (or ...=) in place of the keywords 'wait for', and 'from'. Less words, and '...' traditionally means 'to be continued', or 'wait for a while'. For this Kal code: task getUserFriends (userName) wait for user from db.users.findOne {name:userName} wait for friends from db.friends.find {userId:user.id} return friends would become: task getUserFriends (userName) user ..= db.users.findOne {name:userName} friends ..= db.friends.find {userId:user.id} return friends
- ronreiter 13y agoWhat's up with everyone trying to re-invent coroutines? I personally think people should upgrade JavaScript instead of inventing new languages all the time, since it creates fragmentation.
- jashkenas 13y agoBeautiful work. The `for parallel` notation is a really interesting way of writing it. It seems like a number of folks in this thread have expressed interest in your process -- both of designing the feature set, and of gradually bootstrapping it away from CoffeeScript to become self-hosting. I'd love to hear more, if not here, then in a blog post, perhaps...
- rzimmerman 13y agoThanks! I'm a big admirer of your work, so it means a lot to me to hear that. I wrote up a little bit about this if you are still interested: http://blog.rzimmerman.me/how-kal-compiles-itself/ http://blog.rzimmerman.me/how-kal-compiles-itself/
- pyalot2 13y agoHow many times do I have to say this. Generator/Yields and equivalent constructs don't actually solve the callback problem, they exacerbate it. That is, because you only get to direct one call-level down, but, that's now how you'd code. You'd have some perfectly synchronous code until it hits some infrastructure I/O part some N call layers down, and then now what? You're gonna convert everything to yields? Got any idea how messy that is? Javascript needs proper co-routines. Nothing short of co-routines will solve the issue. Please lookup microthreads, greenlets, fibres, etc.
- jeswin 13y agoI think you have it wrong, generators would solve the problem. If you have asynchronous code N call layers down, then everything above it would be asynchronous as well. So you would only need to yield the first call. Check how Q.nfcall works.
- pyalot2 13y agoThat's a faulty assertion. A generators working principle is that it can resume into the closure if the "caller" is looping over the generator. Let's assume a simple call stack, A -> B -> C. Now C would be a generator, so B has to loop over C instead of just calling C. But what about A? Well if B is now looping, and if yielding out of a loop is how you cooperatively multitask, then A now has to loop over B. So you have to convert the entire call stack from A -> B -> C to A(for ... in B(for ... in C)). You can argue that a compiler can make this invisible, however there are some serious drawbacks with that in that: 1) One solution would be to convert any call into a loop. How do you know which ones are actual calls (stuff like Math.pow etc?) 2) You only convert things that have generators in their call stack to loops, but how do you know that? Both the above scenarios would depend on being able to infer the "generatoricity" of the called symbol. Something which is very, very hard to do for dynamic languages like Javascript. Co-routines work differently. Co-routines save the entire call stack and restore another one on switching to somewhere different. Hence if you have A -> B -> C and C is some I/O that would have to go to some scheduler, then the A -> B -> C call stack is saved, the co-routine would switch to say, Main -> Scheduler, the scheduler would do its work, and when it's ready, it switches back to A -> B -> C where that co-routine left of.
- progx 13y agoBut where is the error handling ? You have some examples with bloated err-returns, but where is that in your kal-code ?
- aufreak3 13y ago(Don't mean to divert this thread from Kal, but this is on the topic of "callbacks are bad" etc.) For some time now, I've been accumulating async patterns I've needed when writing JS code in my monadic IO.js library[1]. The aim of IO.js is to provide higher levels of thinking about sequences of actions without worrying about whether they are async, and with a rich set of error management tools (for ex, exceptions are turned into recoverable conditions in IO.js). The crux of the "callback hell" problem is, contrary to what many have claimed, is not the nesting that results when the callbacks need to be called in temporal order. That much is straightforward to deal with. The "hell" rears its head when you need to coordinate multiple such sequences that are running concurrently. The composable actions you get from a monadic treatment combined with CSP-style channels, are an expressive framework to build abstractions on (tldr - Haskell's implementation is awesome!). For illustration, the framework in IO.js is flexible enough to implement a node.js web server that can express PG's "Arc challenge" concisely (though that challenge is practically obsolete). Take a look at [2]. For a simpler example, `IO.trace` is a straight forward way to generate a trace dump to console of a sequence of asynchronous actions. You don't need to "enable trace" for an entire app. You can choose to trace only a particular sequence. This is pretty neat when debugging. Stack traces are useless when dealing with async processes anyway. [1]: https://github.com/srikumarks/IO.js https://github.com/srikumarks/IO.js [2]: https://github.com/srikumarks/IO.js/blob/master/examples/arc.js https://github.com/srikumarks/IO.js/blob/master/examples/arc...
- mistercow 13y ago>The "hell" rears its head when you need to coordinate multiple such sequences that are running concurrently. This situation is why I wrote DelayedOp: https://github.com/osuushi/DelayedOp https://github.com/osuushi/DelayedOp . Of all the little reusable code bits I've written, this one has ended up in more of my projects than any other. Basically, a DelayedOp is a lightweight manager that runs a callback after its "wait" and "ok" calls have balanced. It ends up being equivalent to _.after(), but it's more natural to use than manually counting your concurrent operations, and it has some conveniences for debugging, so that if a callback never fires, you can find out why.
- egeozcan 13y agoWhat do I do when I want to limit the number of tasks that are run in parallel? I'm talking about something like the queues in the famous async.js. I've seen tame.js trying to solve this by a construct named rendezvous but to me it looked even messier than inline callbacks.
- harlanji 13y agoI came across Galaxy yesterday, linked to from the callbacks/goto discussion. It's an NPM module that gives C# async/await semantics to JS/es6 code (of course it requires the harmony VM). It simply toggles function*/function on things, such as required modules, and provides some extra helpers... the author gives a really nice walkthrough: https://github.com/bjouhier/galaxy https://github.com/bjouhier/galaxy Galaxy does not claim to get rid of callbacks, though... only to help make writing JS/es6 with async/await semantics easier. I've yet to try it out, but the instructions seem clear.
- reustle 13y agoUsing 4 spaces to indent the JS code and 2 to indent the Kal code seems a bit disingenuous
- dogles 13y agoI am a big fan of languages trying to solve callback hell. I use a library in Haxe that allows for similar syntax: https://github.com/proletariatgames/haxe-continuation https://github.com/proletariatgames/haxe-continuation. Haxe compiles to Javascript and is great for node programming...but it has the added benefit of also compiling to c++, php, java, c#, etc., etc. ;)