public
Created

  • Download Gist
fab-next.md
Markdown

changes coming in (fab) v0.5.0

here's a quick outline of some of the stuff i'm working on in the next release of (fab). once i have the internals working again, i'll push a branch for folks to play with.

100% async

right now, (fab) is mostly async, but relies on sync in one case: apps need to return a listener if they require more information to finish. this is a problem because apps may not know if they need more information until they hear from their upstream apps.

for example, a template app needs to return a function based on a string, but that string may come from an async file or http request, so the app can't reliably respond immediately.

to solve this, the use of return as a means of returning a meaningful value is deprecated (but can still be used to short-circuit if needed). instead of each app returning a listener, it passes it as the this context of its response.

so, for example, the fab.tap app would change from this:

fab.tap = function( fn ) {
  return function( app ) {
    return function() {
      fn();
      return app.call( this );
    }
  }
}

to this:

fab.tap = function( fn ) {
  this.call( function( app ) {
    this( function() {
      fn();
      app.call( this );
    });
  });
};

additionally, each app will be able use its length to specify its arity, so that nested functions are no longer necessary to fully curry an app. this means we can trim the above function to this:

fab.tap = function( fn, app ) {
  this( function() {
    fn();
    app.call( this );
  });
};

so not only is this app now fully async, it's less code too.

less HTTP-style overhead

currently, (fab) apps are expected to send a stream of partial JSGI-style objects:

this({ body: "Hello, world!" })();

this({
  status: 200,
  headers: { "content-length": 13 },
  body: "Hello, world!"
})();

this is wasteful for apps that stream many responses, because they need to create an additional object just to send the most common response: a simple body. since the head of a request is usually only sent in one shot, i'm taking it 'out of band', so that responses now look like this:

this( body, head );

combined with the fact that callback functions are now optionally passed as this, we can simplify the above as follows:

this( "Hello, world!" );

this(
  "Hello, world!",
  { status: 200, headers: { "content-length": 13 } }
);

since in both of the above cases this is invoked without a context, the downstream app knows that the connection is closed, obviating the need for a terminating empty call.

this has another awesome benefit: apps that create (fab)-compatible apps are themselves (fab)-compatible, so it's (fab) all the way down.

commas instead of parentheses

(fab) gets a lot of comparisons to lisp due to its, uh, ambitious use of parentheses. but in reality, it's a lot simpler: an app made using (fab) is just a single list of apps that branch based on their arity. there's no nesting, which is something that makes lisp ugly for many.

optionally using commas instead of parens in examples may make this clearer.

The trimmed down syntax shown with fab.tab seems like it will greatly improve both readability and understandability. I look forward to playing with the new syntax.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.