multiple parameters to a callback

52 views
Skip to first unread message

Glenn Block

unread,
Dec 10, 2012, 12:36:26 AM12/10/12
to stream...@googlegroups.com
Hi everyone

Let's assume I have the following code:

self.client.queryEntity('tasks', 'partition1', item, updateItem);

function updateItem (resp,task,err) {
  if (task) {
    task.completed = true;
    self.client.updateEntity('tasks', task, itemUpdated);
  }
}

function itemUpdated (err) {
  ...
}

Now I want to use streamline and ideally get rid of updateItem and itemUpdated. updateItem is passed as the callback for queryEntity, it has 2 params.

Can I use streamline to help clean this up? All the samples I see show the callback having one argument which is passed as the return value, what if there are multiple?

Appreciate your help here!

Thanks
Glenn


Glenn Block

unread,
Dec 10, 2012, 12:43:29 AM12/10/12
to stream...@googlegroups.com
OK reading further through the threads it looks like I found my answer. Basically I have to generate a wrapper.

Bruno, why not support a syntax where if there are multiple args you just get back an object that has an array? I find many examples of apis that return a callback with multiple params, and it would be useful. Better would be a way to have named args, but array will do.

i.e. for my example below it would be something like

var result = self.client.queryEntity('tasks', 'partition1', item, _);
var task = result[1];
if (task) {
  task.completed=true;
  result = self.client.updateEntity('tasks', task, _);
  //process the result
}

or even better might be some way to inline the naming as params of the _ function.

var result = self.client.queryEntity('tasks', 'partition1', item, _(resp,task,err));
var task = result.task;
if (task) {
  task.completed=true;
  result = self.client.updateEntity('tasks', task, _);
  //process the result
}

Thoughts?

Bruno Jouhier

unread,
Dec 10, 2012, 2:05:37 AM12/10/12
to stream...@googlegroups.com
Yes, the solution is to write a wrapper (at least for now). Something like:

Client.prototype.queryEntity2 = function(a, b, cb) {
  this.queryEntity(a, b, function(err, resp, task) { cb(err, [resp, task]); });
}

I did not try to introduce extra syntax for it because there are only a few APIs that require such wrappers. The node.js APIs don't (with the notable exception of fs.exists!!) and the mongodb APIs don't either. And when you have lots of streamline code, most of your calls are to APIs that you created, and you don't need wrappers for those. But of course, some modules do things differently.

I could handle this with a slightly different callback marker. For example client.queryEntity(tasks', 'partition1', item, [_]) to indicate that the result be put in an array.

Note: with the async/await syntax, you will need wrappers around all node and 3rd party APIs because await expects a "deferred". I was more thinking of investing time on async/await than on extensions of the _ syntax.

Bruno

Glenn Block

unread,
Dec 10, 2012, 4:00:15 AM12/10/12
to stream...@googlegroups.com
 
my snippet is wrong actually, the first param is always err in these callbacks.
 
I think await syntax is def valuable. As to multi param callbacks, that may not be super common in node, but for modules wrappong 3rd party HTTP apis, it can be pretty common.

Aseem Kishore

unread,
Dec 10, 2012, 3:06:44 PM12/10/12
to stream...@googlegroups.com
Ooh, the [_] syntax is really elegant.

var vals = someAsyncFunc(foo, bar, [_]);
var resp = vals[0], body = vals[1], type = vals[2];

It'd also work really nicely w/ CoffeeScript:

[resp, body, type] = someAsyncFunc foo, bar, [_]

I'm not aching for this though. In our case too such APIs are pretty rare, and making a wrapper isn't a huge deal, so if you have other stuff on your plate, totally cool. Just chiming in that I like this syntax a lot.

Aseem

Glenn Block

unread,
Dec 10, 2012, 4:40:25 PM12/10/12
to stream...@googlegroups.com
I will settle for an array, but I would LOVE named params. Maybe I can
contribute it?

Aseem Kishore

unread,
Dec 10, 2012, 5:58:09 PM12/10/12
to stream...@googlegroups.com
One problem with the _(resp, body, type) syntax is that this'll be invalid JS if err/resp/body/foo aren't defined variables already. Maybe that doesn't matter since Streamline will check and transform that, but e.g. the code will fail JSLint.

One way to achieve named params would be strings, e.g. {_: ['resp', 'body', 'type']}, but strings always feel lame for cases like these.

Another way is e.g. {resp: _, body: _, type: _}, but that's verbose and repetitive. You could do {_: {resp: null, body: null, type: null}} or whatever (or maybe you can replace the nulls with default values), but that gets super complex.

That's why I personally think the array syntax is beautiful: simple and elegant.

Just my two cents. =)

Bruno Jouhier

unread,
Dec 10, 2012, 7:40:23 PM12/10/12
to stream...@googlegroups.com
Yep, it works great with languages that have destructuring assignment. CoffeeScript has it and it looks like Harmony will too (http://wiki.ecmascript.org/doku.php?id=harmony:destructuring).

If it's not too difficult to implement I'll try to cook it in.

Bruno

Bruno Jouhier

unread,
Dec 10, 2012, 7:54:59 PM12/10/12
to stream...@googlegroups.com
For object literals I have a slight preference for {resp: _, body: _, type: _} and {_: ['resp', 'body', 'type']} comes second.

The repetition of _ is not ideal but it remains compact and we already end up with so many underscores anyway :-(. The other form is slightly more compact but I don't like the quotes that much.

As Aseem mentions, the _(resp, body, type) looks like a function call with resp, body and type parameters which may or may not be defined in the scope. This may be confusing, especially if there are already variables with these names in scope.

Bruno

2012/12/10 Aseem Kishore <aseem....@gmail.com>

Glenn Block

unread,
Dec 11, 2012, 12:10:03 AM12/11/12
to stream...@googlegroups.com
Sure it 'could' be confusing but you instruct people. Also you could catch when you parse whether it was defined.

As to it breaks from js perspective, you need to precompie streamline files anyway.

The underscore syntax looks ugly. I could settle for array though.

Bruno Jouhier

unread,
Dec 12, 2012, 1:33:43 AM12/12/12
to stream...@googlegroups.com
I agree that the _ syntax is not ideal but this is the best I could come up with to get a terse result and work seamlessly with other language tools (CoffeeScript, syntax coloring in editors, etc.).

The [_] marker looks rather natural for arrays. Object literals is trickier so maybe I should start with the array idea and see how it goes.

BTW, the proposals that I have seen on EcmaScript side are usually aligned on browser callback APIs (separate callback and errback params) rather than on the node API style. So, if something lands in the language someday (which I hope), it will require wrappers around all node.js APIs.

If you write thin logic layers around lots of node APIs, the wrappers are a bit of a problem. But when you start having thicker logic (which is what streamline is really designed for) the wrappers become less of a problem because the bulk of your code ends up being streamline functions calling other streamline functions. This is why I did not spend too much energy on the wrappers (also we did not run into the problem ourselves because the APIs that we use in our product don't return multiple results). So this can be an annoyance when you start but once you have the wrappers in place, the rest should go rather smoothly.

Bruno
Reply all
Reply to author
Forward
0 new messages