This 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?
It'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 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.
Unfortunately 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.
It'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.
I'll stick up for the "wait for" syntax here. It seems a lot cleaner to me than trying to shoehorn asynchronous handling into assignment, with all the edge cases that entails.
I'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?
Are 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.
There 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 or another small, understandable library.
Respectfully, 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.
I'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.
It'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 :)
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.
On 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.
You're right. I pretty much just blurted out the first thing that came to my mind when I read about it, and what I said was equivalent to garbage. It was completely uncalled for and I apologize to everybody in this forum for lowering the level of discourse, much less crapping over someone's hard work and pride.
Excellent 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.
Definitely 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:
A 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.
As 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!).
You can do it using monadic augmentation. Or aspect oriented programming.
In plain english, make a function that takes two functions makeADoThingFunctionThatHandlesErrors(doThing, handleError)
and returns a new version of the function that is internally
wrapped in a try catch block with the handleError function getting called from the "catch" block. This is relatively straightforward to accomplish using closures/high order functions. This is one utility function you write once.
Finally you can do this with a whole "monadic" api such as jquery- create a function that loops through all the methods on an object prototype and wraps them in an error handler, returns a new version of the prototype you can inherit from.
Or instead of doing all that, you just use some library with promises (such as Q, or jQuery) that implements all the above, and all you need to do is write a single error handler function, and any error that gets thrown by any function in a promise chain gets caught and sent to that function.
wait for data from fs.readfile 'test.txt'
print data.toString
and readFile calls back with an error (the first argument is non-null), the error will be thrown just before the print statement. So print will not execute and you'll get a stack trace. The cool thing is that you can do these async calls within try blocks:
try
wait for data from fs.readfile 'test.txt'
print data.toString()
if data.length > 0
wait for data2 from fs.readfile 'test2.txt'
print data2.toString()
else
print 'too short'
catch e
print 'there was an error'
wait for resp from db.save()
Will do what you expect - abort after either wait for if it fails and run the catch clause. Think about how you'd do that in JS:
var error = null;
var data, data2, resp;
fs.readFile('test.txt', function (err, data) {
if (err) return handleErr(err);
console.log(data.toString())
if (data.length > 0) {
return fs.readFile('test2.txt', function (err, data2) {
if (err) return handleErr(err);
console.log(data2.toString());
return closeout();
});
} else {
console.log('too short');
return closeout();
}
});
function handleErr(err) {
console.log('there was an error');
return closeout();
}
function closeout() {
return db.save(function (err, r) {
if (err) throw err;
resp = r;
});
}
Oh 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.
Thanks. 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.
*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.
You do know that jQuery isn't a monad, right? That's the second time in this thread that you've called it one. Simplest demonstration that it isn't: try defining join.
jquery-like.
I never claimed that that jquery is a monad. I know it isn't. But also, I don't want to be one of those guys that throws around the word monad expecting everyone to understand what I'm talking about.
as for defining "join", help me understand. How is jquery "add" not essentially that? And why pick the fmap,join formulation instead of the bind,return formulation of a monad?
jQuery's add function has a few different formulations depending on what argument you pass, but it's basically either M a -> a -> M a (if you pass it an html string, an element, or a selector) or M a -> M a -> M a (if you pass it another jQuery object) where here M refers to the jQuery wrapper and the first argument refers to `this` (obviously these type signatures are an approximation since JavaScript doesn't really work this way). join is M (M a) -> M a, which is very different.
The reason I picked join is because (in my view, anyway) it's the easiest demonstration of how jQuery is not a monad. There's no way to even get something of type M (M a) in jQuery, because the jQuery lifting operation is idempotent. The same exact problem exists with return, but I've found that people have a hard time seeing it with that example.
The problem I have with you referring to jQuery as a monad, even by analogy, is that jQuery really really isn't a monad. It's only very loosely analogous, and that analogy is more likely to teach people the wrong things about monads rather than the right ones.
Well that is a fair enough concern, and I notice I used the word "Monadic" to describe jquery carelessly, to mean "Monad-like" though that isn't really what "Monadic" means.
For the case in hand though, you can get to almost but not quite really technically a monad, and still cure most of the nested callback headaches. One way I think about monads is they are a strategy for turning nested functions into sequentially composed functions. Which is, pretty much what we want, right?
I just don't think it's useful to use the word monad to describe the strategy you're suggesting. I'm not criticizing your suggestion, I just don't think it has anything to do with monads.
More to the point, I don't understand why we (HN and the JS community at large) keep having this discussion. Coroutines have been around since the 60s. This is a solved problem.
because you can't use coroutines in client-side javascript yet, without some backpiler, and people will disagree on what the proper reaction to that should be.
How 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.
Is 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
I 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.
It'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!
Thanks! 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).
Coming 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.
This 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 :-)
Thanks! I was wondering if someone would make that comparison. I saw async-await a little after I started working on this and felt it was good confirmation that this was actually a reasonable idea.
I quit engaging at shoprite and currently I build $35h - $80h...how? i am operating online! My work did not precisely build Pine Tree State happy therefore i made a decision to require an opportunity on one thing new… when four years it absolutely was therefore onerous to quit my day job however currently i could not be happier. Heres what I do, www.jobs34.ℂom
I'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?
The 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.
Interesting. 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.
Does 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?
Try http://www.neilmix.com/narrativejs/doc/ -- "a small extension to the JavaScript language that enables blocking capabilities for asynchronous event callbacks".
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.
Thanks 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.
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
Promises are a completely sufficient solution to handle asynchronous code in my opinion and there are already several great libraries for this in JavaScript. I don't get it why would I want to switch to a new language just because of that one feature.
Sorry 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.
Of 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!
I 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
What'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.
Beautiful 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...
129 comments
[ 5.0 ms ] story [ 182 ms ] threadIs this a fork of the CoffeeScript compiler? Will it benefit from upstream changes/features?
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) if you can.
If you get a chance (and use TextMate or Sublime Text), please give syntax highlighting a try (https://github.com/rzimmerman/kal.tmbundle)!
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 or another small, understandable library.
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.
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?
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.
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.
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.
Apologies if you saw these already. I'll add something like what you suggested, though.
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.
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...)
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!).
In plain english, make a function that takes two functions makeADoThingFunctionThatHandlesErrors(doThing, handleError)
and returns a new version of the function that is internally wrapped in a try catch block with the handleError function getting called from the "catch" block. This is relatively straightforward to accomplish using closures/high order functions. This is one utility function you write once.
Finally you can do this with a whole "monadic" api such as jquery- create a function that loops through all the methods on an object prototype and wraps them in an error handler, returns a new version of the prototype you can inherit from.
Or instead of doing all that, you just use some library with promises (such as Q, or jQuery) that implements all the above, and all you need to do is write a single error handler function, and any error that gets thrown by any function in a promise chain gets caught and sent to that function.
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.
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/
*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.
as for defining "join", help me understand. How is jquery "add" not essentially that? And why pick the fmap,join formulation instead of the bind,return formulation of a monad?
The reason I picked join is because (in my view, anyway) it's the easiest demonstration of how jQuery is not a monad. There's no way to even get something of type M (M a) in jQuery, because the jQuery lifting operation is idempotent. The same exact problem exists with return, but I've found that people have a hard time seeing it with that example.
The problem I have with you referring to jQuery as a monad, even by analogy, is that jQuery really really isn't a monad. It's only very loosely analogous, and that analogy is more likely to teach people the wrong things about monads rather than the right ones.
For the case in hand though, you can get to almost but not quite really technically a monad, and still cure most of the nested callback headaches. One way I think about monads is they are a strategy for turning nested functions into sequentially composed functions. Which is, pretty much what we want, right?
More to the point, I don't understand why we (HN and the JS community at large) keep having this discussion. Coroutines have been around since the 60s. This is a solved problem.
For this Kal code...
Here's a pseudo-ish implementation in pseudo-ish Haskell. 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!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).
Thanks for your hard work!
[1] - http://msdn.microsoft.com/en-us/library/vstudio/system.threa...
[2] - http://msdn.microsoft.com/en-us/library/vstudio/hh191443.asp... and http://msdn.microsoft.com/en-us/library/vstudio/hh156528.asp...
eg.
Specifically, the section on "backcalls": http://livescript.net/#backcallsIt'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.
Essentially self-compiling compilers can "remember" things that are nowhere to be found in the source code.
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.
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.
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.
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
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.
For this Kal code:
would become: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...