Function.prototype.toString to discover function dependencies

James Burke jrburke at gmail.com
Mon Sep 20 14:45:15 PDT 2010


On Sun, Sep 19, 2010 at 12:41 PM, Mark S. Miller <erights at google.com> wrote:
> Given source code, of course, either recognition trick works. Given only
> meaning preserving source code, which is the most I was willing to propose
> on that strawman page, these recognition tricks fail
> <http://wiki.ecmascript.org/doku.php?id=strawman:function_to_string#discussion>.
> Would we be willing to specify enough fidelity with the original source code
> that your trick would work? I don't know. Perhaps AST preserving? Perhaps
> preserving of some abstraction over equivalent ASTs? I would like to clean
> up Function.prototype.toString for ES-Harmony. Opinions?

If "meaning preserving source code" had qualifications like:

1) If line returns are removed, comments must be removed.
2) String literals need to stay string literals.
3) The number of function arguments must stay the same, and function
argument names and their use within the function must be preserved.

that might be enough to give implementors enough flexibility but still
allow the require dependencies to be found? Although I am not a
language expert, maybe there are still holes with those
qualifications.

#3 could be relaxed to "The number of function arguments need to stay
the same. The name can change, but code inside the function needs to
change to use the new name, and the use of those names needs to be
preserved".

That would require a bit more work from my side. If the toString
converted the function to something like function(r,e,m) {var
f=r('foo'),b=r('bar');}, then it would require more work to pull out
the r function arg. A bit less efficient, but doable. Probably not too
bad given that this should just be used in a "source code loading"
form, and not something that is used after optimization. For
optimization it will be common to place many require.def calls into
one file, so names for the modules and the dependencies can be pulled
out from the source and injected into the optimized require.def call.

But if it is all the same to implementors, then I prefer the first,
stronger wording of #3.

I went ahead and put support for this require.def toString approach
into the RequireJS implementation to try it out. There are still some
edges to clean up, but we will see how it goes. Right now I assume the
above qualifications on the toString() form. This seems to work out,
but more testing is needed. For the apparently small number of
implementations that do not preserve some usable string for
Function.prototype.toString, then the advice will be to use an
optimized/built version of the code that has pulled the dependencies
out already, or to use use the other syntax supported by RequireJS:

require.def(['foo', 'bar'], function(foo, bar){
    //return a value to define the module. Alternatively,
    //as for 'exports' as a dependency in the dependency
    //array and specify it as a matching function arg
    //if dealing with a rare circular dependency failure case.
    return function(){};
});

James


More information about the es-discuss mailing list