Tuesday, April 1, 2014

Thunks and co with ES6 generators

A thunk is the output of a transformed node.js-style asynchronous function. The transformed function (aka the thunkified function) is meant to work with a generator wrapper. Here is the generator wrapper I am talking about:
co(function*(){
  ...alot of synchronous looking code...
})()
That generator wrapper takes the output of a thunkified async function call in a yield context and passes the ultimate results of the async call back to the original yield location; so code like this works (within the generator wrapper):
output = yield thunkfiedAsyncFn(args...)
Where node.js asynchronous functions are called with a few arguments plus one callback function to receive the output of the async operation, a thunkified node.js function call takes the original arguments MINUS the callbcak function and outputs a thunk function. In the above example what you are yielding to the generator wrapper is the thunk function. Here is a full example of reading a list of files in series: As you can see this is very different from how you would need to do it with the async module. For example, you can directly use the array subscript i of the fns array (normally you have to worry about the closure over i in a callback always being equal to 4.

To do the same async work in parallel you collect an array of thunk functions and yield that array. Example:

Saturday, August 4, 2012

Just published v1.1.0 of my framing protocol module for node.js. https://github.com/lleo/node-frap I rewrote the input parsing routine completely for v1.1.0. It wasn't broken before, but the current version is much cleaner/better looking code. I remove gobs of what I've come to call vomit code. All the verbosity for debugging and assert-bombing to die close to a bug (old C-coder debugging style of mine). Lots of lines-of-code reduction. Makes it easier to read casually. I implemented a lot of BDD tests, based on the mocha framework. I wrote better benchmark scrips. Better but not very good. Overall, I'd say it is more stable and healthier code than v1.0.0.

Saturday, June 23, 2012

IEEE 754 may not be such a kluge I thought it was

I just found out something elegant about double floating point numbers... or maybe this is just a Javascript thing.

function log2(v) { return Math.log(v)/Math.LN2 }
log2(Number.MAX_VALUE) //=> 1024
The Log base 2 of the Maximum double floating point number is 1024. There is something elegant about that. My respect for IEEE 754 just went up.

Friday, September 23, 2011

Again: exports and module.exports in JavaScript Modules

I reread my posts and realized that I haven't been clear as I'd like.

If you require() a module there are a couple simple rules:
  1. you don't need to put the '.js' on the end of the file.
  2. if you require('./my_module') the file must be in
    1. ./my_module.js or
    2. ./my_module/index.js
  3. if you require('my_module') the file must be in
    1. ./node_modules/my_module.js or
    2. ./node_modules/my_module/index.js or
    3. or a node_modules directory toward root (.. or ../.. or ../../.. till /node_modules)

As for the module file itself, you must set the object to be returned from the require() call. This is the part that flummoxed me.

It is simple, in your module there is a module variable automagically. That module variable points to an object that is pre-populated with many properties. Just do a console.dir(module) in your empty module file to see it all.

The object that gets returned from the require() call is pre-allocated in the module.exports property. There is also a variable called exports that contains the very same object that is in module.exports. If you assign a new object to the exports variable, eg exports = {};, that new object will NOT be exported as it is not the same object that is in module.exports. Think of it as if there is a invisible exports = module.exports = {}; line at the beginning of your module. The exports variable is only there for your convenience and only the object pointed at by module.exports matters.

This is simple and I found no one who said it straight out. There was crap about exports being an "alias" for module.exports and other balderdash. If you want to create your own elaborate exported object just do this:
exports = module.exports = {
 ... my big-ass exported object ...
};

Thursday, September 22, 2011

CommonJS exports spec ambiguity

I have just been reading the spec for CommonJS. In the 1.0 Spec it refers to the exports variable and object interchangeably.

  1. In a module, there is a free variable called "exports", that is an object that the module may add its API to as it executes.
  2. modules must use the "exports" object as the only means of exporting.

There is no mention of "module" or "module.exports".

I've also realized I am a blithering idiot. I put console.dir(module); in an empty module and I saw that it was populated with a great many things. Most pertinently, module has a property named exports already initialized to an empty object. If you add something to module.exports like module.exports.foo = 'bar'; then console.dir(exports); will output { foo : 'bar' }. It is sad how much my coding skills have atrophied the last few years. I used to be rather sharp ... oh well.

Tuesday, September 20, 2011

Nodejs: module.exports and exports

I have just had a rough time learning how to create my own module. The problem is that I can't move on just knowing How to get something to work, I need to know Why. It is some form of programmer paralysis; worse than writers block. I needed to know how/why exports worked in Nodejs modules.

Requiring modules is simple

var m = require('./my_module');
m.myFunc(foo, bar);
The file needs to be "./my_module.js", with the following exports line:
var myFunc = function () { ... };
module.exports.myFunc = myFunc;
The Why is the hard part. You can't do exports = {}, but you can do module.exports = {}. Turns out module is the "global" namespace in an require() file. exports is some sort of "alias" for module.exports (I haven't figured that out). What this means is that exports.myFunc = myFunc; is OK, but exports = {myFunc: myFunc} is NOT OK, BUT module.exports = {myFunc: myFunc} is OK. Basically, I've decided not to use this pseudo-whatchamacalit "alias" type thing exports. I'll just use module.exports. Additionally, it is probably best to use the form:
module.exports.myFunc = function () {
...
};
for all exported functions inside ./my_module.js