Thursday, March 8, 2012

Quick Coffee

A very short post today. After having discussed and thought about the state of client communication a little while ago, I mentioned that I'd be doing some semi-serious work in node.js. Mainly because they seem to do Websockets Properly™.

So I downloaded node, and npm[1], and got ready to go through a tutorial or two. It was pretty fast going because I'm already fairly experienced with JS[2], but the reading for one in particular was surreal. Half of the thing was written for an audience that's only just heard of higher order functions. It also involved a lot of server restarting, which I found annoying enough to look for relief. That's a check, at least.

Sorry, I'm getting off track here. Anyway, once I got refreshed with the examples and moved on to trying to code up something for myself, it took all of 10 minutes and about a file and a half before I remembered exactly why I mostly use parenscript these days. Javascript is... well... it's ugly. It doesn't really seem ugly when you just look at examples, but if you try to actually use it for realzies, it'll take surprisingly little to get to an annoying obstacle. Whether you'd really like an optional/rest argument somewhere, or you'd like to have a function return implicitly, or you'd like to do some non-trivial string templating, you will either be annoyed or you'll need to find another way.

There's no real way to solve this from within JavaScript either, which is why I'm considering code transformers. There's the obvious, already mentioned, parenscript[3], and there's a surprisingly expressive alternative JS syntax called Coffee Script which you've probably heard all about.

I haven't quite got Emacs highlighting it properly, but it seems to do nearly as well as parenscript at abstracting the annoying parts.

# function definition
square = (num) -> num * num                               
# optional argument and string templating
greet = (subject = "world") -> "Hello, #{subject}!"     
# rest arg and array comprehension
squares = (numbers...) -> square n for n in numbers     
# multi-quote string
content = """
<div id="content">
  <span class="quote">Blah!</span>
</div>
"""

That surprisingly terse block of Coffee Script expands out to

var content, square, squares, greet,
  __slice = Array.prototype.slice;

square = function(num) {
  return num * num;
};

greet = function(subject) {
  if (subject == null) subject = "world";
  return "Hello, " + subject + "!";
};

squares = function() {
  var n, numbers, _i, _len, _results;
  numbers = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  _results = [];
  for (_i = 0, _len = numbers.length; _i < _len; _i++) {
    n = numbers[_i];
    _results.push(square(n));
  }
  return _results;
};

content = "<div id=\"content\">\n  <span class=\"quote\">Blah!</span>\n</div>";

Granted, it misses some big ones[4], but still.

I kinda like it.


Footnotes

1 - [back] - As an aside here, I have to note that I seem to have no patience left for languages without good package managers. I'm pretty sure this is a new development because I've done some work in Erlang, and there's this vague memory kicking around my head of a time before quicklisp, but there you have it. Luckily, npm is pretty good and getting better fast.

2 - [back] - Having done heavy development in jQuery, and some playing with Rhino and Jaxer back when those "were new" and "existed" respectively.

3 - [back] - Which I'd prefer not to default to since the whole point of this exercise was to get away from Lisp for a little while. It may still end up winning, but I want to at least look at an alternative first.

4 - [back] - Macros, obviously, but I've also got surprisingly used to prefix notation and homoiconicity. There's also the fact that Coffee Scripts' highlighter is misbehavin', and coffee has nothin' on slime, and I'd have to give up paredit use to go back to syntactic whitespace. In fact, I'm going to stop thinking about this now because it's almost depressing how many things non-lisps are missing that you really wouldn't think are a big deal until you get the option to lose them.

2 comments:

  1. Been wanting to learn a bit about this kind of web client side work (I'm actually a hardware engineer), and I happen to be working my way through The Little Schemer, so I'm interested in where you find yourself, betwixt Parenscript and CoffeeScript.

    Always interested in your posts. Good stuff.

    ReplyDelete
    Replies
    1. Pardon the late reply.

      I'm actually still working on a post comparing the two, and was entertaining this odd delusion that I could get it finished in a reasonable amount of time.

      Short version: I'm leaning towards parenscript. It has less to do with the fact that Coffee Script is poor, and more to do with the fact that Common Lisp provides a level of syntactic abstraction that I've unknowingly come to expect from languages (and most languages, CS included, don't offer the same).

      You could definitely get work done with either, and Coffee Script is certainly nicer to work in than JavaScript, but I really feel hamstrung not being able to define my own `define-...` and `with-...` forms.

      Delete