Recent submissions

Comment · 14 years ago
In both examples, the function is only allocated once, no matter how it's instantiated.

Where you have to be careful is if you have a function that's being called repeatedly and it contains a function instantiation -- that function will be reallocated each time.

   [1,2,3].forEach(function(x) {
     return (function(a, b) { return a * b })(x, 2)
   })
Will repeatedly allocate that inner multiplication function, vs:

  mul = function(a, b) { return a * b }
  ;[1,2,3].forEach(function(x) {
    return mul(x, 2)
  })
Will only allocate that multiplication function once.
Comment · 14 years ago
In this case, it's not language lawyering. All JavaScript environments "do the right thing" with regards to ASI -- it works in all target environments as of the present day. JSMin is not a target environment, it is a minifier that happens to express some strongly-held opinions of its author.

That said, it's hard to program to a spec that does not (officially) exist yet, and doubly so if there's not clear "opt-in/out" path for future versions. Since, as a developer, I can't control what the committee adds or removes from the spec, or what they might break, I can only do the best I can with the language as it is -- not breaking existing code in future versions of the language is the committee's job.

Comment · 15 years ago
I'm increasingly a fan of local named functions in JS, vs. pulling callbacks entirely out of scope. An example:

    function compile(filename, ready) {
      return fs.readFile(filename, make_fn)

      function make_fn(err, data) {
        if(err) return ready(err)

        ready(null, new Function(data))
      }
    }
Which neatly addresses the desire to retain closures, while avoiding unnecessary nesting.

Also, whenever possible, I like to nix callbacks by using Function#bind:

    res.on('data', accum.push.bind(accum))

    // vs:
    res.on('data', function(data) { accum.push(data) })
Comment · 15 years ago
Comment · 15 years ago
Comment · 15 years ago
Comment · 15 years ago
this looks really cool. i was actually working along the same lines (https://github.com/chrisdickinson/tempisfugit) to get a pure JS git implementation, though now I'm a little disconcerted since your project looks so fully featured :) One question: I noticed that you got dakongai's js-deflate library working with git -- I had tons of problems with getting it to read deflated git objects (mostly, that it wouldn't deflate them at all), and I had to turn to jxgcompressor (eventually) to get inflate to work. Before I saw this, I was planning on shimming in compression support by including a simple flash-to-js bridge; but if dakongai's library works I'd definitely rather use it. Again, awesome work!
Comment · 15 years ago
Yes and no -- it's not absolutely necessary; I could've written it similarly without turning the callback-accepting functions into emitter-returning functions. It would have felt gross to do so, though. The downside I see with using straight callbacks that accept error and data arguments is that they conflate the logic of what that callback is actually attempting to do with the error-checking of the calling function. For example, my `baseDirOkay` method shouldn't care whether or not the calling `fs.stat` function succeeded or failed -- it should only care that the data it was passed is or isn't a directory. It shouldn't be called at all if the path was not valid. With an EventEmitter api, I can rely on the emitter itself to tell me whether or not to even call my `baseDirOkay` function, instead of having to conflate that logic with my method.

This seems like a tiny gain in readability, but it means that I don't have to make a decision between putting the error/success logic of `fs.readFile` in my method (where it does not go) and my calling function (where it probably does not go, and where it would incur unnecessary nesting -- and the finagling of the `this` variable that that incurs).

This may just be my taste -- but I find designing around (and reasoning about) EventEmitter-type API's much easier.

Comment · 15 years ago
re: cutting down on callback nesting / spaghetti code.

It can be hard to avoid; and having the community put together a PEP-8 style "best practices" to avoid creating nested code is one of my fondest dreams.

That said, I've written my fair share of [spaghetti code](https://github.com/chrisdickinson/tempisfugit/blob/master/li...) in Node, mostly because JavaScript seems to lend itself to slapping together nested callbacks without slapping you on the wrist for writing unreadable code.

In my experience, the best way to cut down on spaghetti code is to design your API around the [EventEmitter](http://nodejs.org/api/events.html#events.EventEmitter) object. Consider this adaptation of the linked spaghetti code: https://gist.github.com/f8533ff57844b1e54558

Note that in the application code, there are no nested callbacks -- they're merely concerned with validating the incoming data and passing the baton on to the next responder. Bonus points: the methods are in the order of their ideal execution. Clients using the code can just do the following:

    var validator = new RepoPathValidator(path);
    validator.on('data', function(repoData) {
        // do whatever needs to be done with the repo.
    });

    // redirect all errors to console.error
    validator.on('error', console.error.bind(console));
I'm very fond of using this method to destroy nested code -- I'm not sure how it's thought of in the community at large, though (part of the reason I'm so eager for the community to put together the aforementioned PEP-8 style "best practices" guide!)
Comment · 16 years ago
something like this:

  var session = require('session'),
      models = require('models'),
      template = require('template');

  function main(request,response){
    session.start(
      models.getEntries.bind(models,
        template.render.bind(template, 'blog',
          response.write.bind(response))));
  }
would be easy to put together with node.js; it's functionally equivalent to the above (though it assumes that data comes into the template.render call as the last argument(s)), and neatly avoids too much nesting.
Comment · 16 years ago
Hi -- this is chrisdickinson.

One of Wilson's goals is to be comfortable for Djangonauts who, for whatever reason, need to write Node.js code. To that end, the ORM, view layer, and template system are similar to Django to ease use in that particular case.

The other boon to having a largely cross-compatible template language is that it allows a bit of bootstrapping to occur for Wilson projects -- Wilson could conceivably make use of Django's admin templates at some point, if that's the direction it's going to head.

However, Wilson does diverge pretty rapidly from Django in other areas -- it borrows Django's concept of apps, but in Wilson apps are designed to be pluggable; you can install a single app multiple times under multiple aliases, reopen app instances from the project level and change their settings and models before they're finalized, etc. Within the context of an app, you interact with other apps through "externals" that are resolved at project-level.

The other major difference is that wherever possible, I'm hoping to keep the libraries that constitute Wilson separate -- and wherever it makes sense, to make them also operable in-browser. To that end, Platoon (the testing framework), Plate (the template language), Escaperoute (the router), Pieshop (the ORM), and postpie (the ORM adapter to Postgres) are all kept as separate libraries; Pieshop and Plate are actually designed to be run in-browser as well, in preparation for the eventuality of needing to interface nicely with a Wilson app from the client-side.

So in summary: Wilson isn't a one-to-one port of Django -- it's heavily Django-inspired -- but aims to diverge wherever it is sensible to do so.

Comment · 16 years ago

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton