Resource "using" in JavaScript
Based on a discussion in v8-users I was playing with a nice style for lifetime-bounded resource uses in JavaScript. I don't actually have any practical need for it at the moment, but thought I'd share.
Imagine you have some type Resource that is "expensive" - typically, it holds onto something that you want to get rid of as soon as you're done using it. An example might be a file descriptor or a memory buffer. In JavaScript or C# you generally rely on garbage collection to detect that you're done with something and release the resource, but in some circumstances you want to do so explicitly, so the Resource type exposes a method release() that you can call. Perhaps, behind the scenes, this is a host object and this will cause the native resources to be freed. The contract will usually be that using Resource past this point will raise exceptions, so it assumed you know what you're doing.
The basic JavaScript usage would then be:
var res = new Resource(); res.doSomething(); res.release();
That's fine, but since you really don't want to forget to call release() and if the logic in between is complicated - with error cases, multiple return paths, etc. this can be tricky to get right. In the C++ world this is called RAII, but in JavaScript with GC the preferred pattern is:
var res = new Resource(); try { res.doSomething(); } finally { res.release(); }
This is more robust, but a lot of typing. The C# language provides a using keyword to give a nice syntax for this:
using (var res = new CSharpResource()) { res.doSomething(); }
Which, assuming Resource implements IDisposable, is syntactic sugar for the try/finally/release(), give or take.
As Sven Panne points out in the v8-users thread:
In a language with first class functions, having a special syntactic construct is not even necessary, see e.g. 'bracket' in Haskell (http://www.haskell.org/ghc/docs/latest/html/libraries/base-4.5.1.0/Control-Exception.html#v:bracket). So if you want to have tight control over the lifetime of your external objects/resources, wrap your usage patterns into higher-order functions and enjoy... :-)
The direct translation of Haskell's bracket to JavaScript is:
function bracket(before, body, after) { before(); try { body(); } finally { after(); } }
Which would be used like:
var res; bracket( function () { res = new Resource(); }, function () { res.doSomething(); }, function () { res.release(); } );
Yay, no need for new syntax. But still wordy, and the variable leaks outside the bracket() call unless you wrap the whole thing in an anonymous function. If we're focused on the specific use case of resource types that follow a common pattern like having a release() method, can we do better? Yep:
function using(res, body) { if (!res || typeof res.release !== 'function') new TypeError("Expecting object with release() method"); try { body(res); } finally { res.release(); } }
Which would be used like:
using(new Resource(), function (res) { res.doSomething(); });
... which is looking almost pleasant to code with. I mean, if you're coding in modern idiomatic JavaScript, function () {} is invisible to you anyway. Building any sort of syntactic sugar for this into ECMAScript would therefore be premature, unless there was widespread use of this pattern already, and I'm not aware of such - but then, I don't hang out with the cool Node.js kids.
Now I just wish I had a use for this pattern in one of my projects.
Comments
Post a Comment