Function.prototype.toString to discover function dependencies

James Burke jrburke at gmail.com
Wed Sep 15 17:24:52 PDT 2010


First time posting to the es-discuss list:

Over on the CommonJS list, there is a thread about how to provide a
module format that works in today's browsers. The traditional CommonJS
module format cannot run in the browser via script tags without a
transform, and some of us want a format that will work without
transforms but can be easily hand-coded.

Tom Robinson made the following suggestion, is this an acceptable use
of Function.prototype.toString:

require.def(function (require, exports, module) {
    var foo = require('foo'),
        bar = require('bar');
});

Where require.def would call .toString() on the function passed to it,
regexp for the require() calls, then make sure to load those
dependencies before executing the function that defines the module.

So the toString() does not have to be an exact copy of the function,
just enough that allows the require() calls to be found.

I am leaving out a bunch of other stuff about the browser-friendly
module format (for instance there is a transform for this format to
allow grouping more than one module in a file for optimized browser
delivery and that form does not use .toString() and this approach
*would not* be used on minified code), but the main question for the
es-discuss list is:

Is this an acceptable use of Function.prototype.toString? What
problems would there be now or in the future?

What I have found so far:

The ECMAScript 3rd and 5th edition specs say the following:
------
15.3.4.2 Function.prototype.toString ( )

An implementation-dependent representation of the function is
returned. This representation has the syntax of a FunctionDeclaration.
Note in particular that the use and placement of white space, line
terminators, and semicolons within the representation string is
implementation-dependent.

The toString function is not generic; it throws a TypeError exception
if its this value is not a Function object. Therefore, it cannot be
transferred to other kinds of objects for use as a method.
------

In a 2008 es-discuss thread[1], Erik Arvidsson thought the
"implementation-dependent" part allowed for low-memory devices to not
keep a reversible implementation in memory.

A test was run in a few browsers to test the approach[2]: modern
desktop browsers (including IE 6+) give a usable toString() value, and
there are many mobile browsers that also work well: Android, iOS,
Windows Mobile, webOS and latest BlackBerry. So far BlackBerry 4.6 and
some version of Opera Mobile may not, and there are some like Symbian
and Bada that have not been tested yet.

So one issue is not universal browser support, but enough of today's
browsers both on desktop and mobile that it may make sense using it
going forward. While the spec technically allows an implementation to
produce something that might cause the above mentioned Function
toString() approach to fail, it seems in practice it may be workable.

I am a bit wary of the approach, but initial testing seems to indicate
it may work, so I am looking to have an expert review done before
proceeding with the approach. If any of you have other other
information or concerns it would be good to know.

James

[1 ]Thread starts with this post:
https://mail.mozilla.org/pipermail/es-discuss/2008-September/007632.html

[2] Browser test page:
http://requirejs.org/temp/fts.html


More information about the es-discuss mailing list