In my second day at Catalyst, we did some programming koans, and I learned something really interesting-- JavaScript, every function has a toString()
and the Function
constructor can create functions from strings.
Exploring the relationship between functions and strings
Let's say we've already defined a function called "product" in the browser console:
var product = function(a, b) { //gratuitous comment return a * b; } product(3, 4); //returns 12
We can see the string representation of our function by calling the toString()
method:
product.toString(); // returns the following: "function (a, b) { //gratuitous comment return a * b; }"
Build functions from strings with new Function
This is where things start to get fun. First we'll put the entire function body in a string, using \n\
to escape our new line. Then we pass the argument names and function body into the new Function
constructor, each wrapped in strings. This creates a new function, named f, that returns the product of its arguments, just as product()
does.
var s = " //gratuitous comment\n\ return a * b"; var f = new Function("a", "b", s); f(3, 4); //returns 12 f.toString(); //returns the following: "function anonymous(a, b) { //gratuitous comment return a * b }"
Continuing down the rabbit-hole
Strings can be sliced, modified, messed with to create other functions. By doing a substitution on the string, we can make a function that adds instead of multiplying.
var string2 = s.replace('*', '+'); var f = new Function("a", "b", string2); f(3,4); //return 7
The next step would be to create a function that takes a string as input and returns an array of strings-- one string for each parameter and one for the function body. The two variable version of this is as follows:
var crazy = function(str) { //Note: JS regex don't work properly on multiline matches //This code can be simplified for future browsers that do var unblank = function (x) { return (x !== ") && (x !== "}"); } fbody = str.match(/.*/gm).filter(unblank); fbody[0] = fbody[0].match(/\((.*)\)/)[1]; args = fbody.shift().split(', '); fbody = fbody.join('\n'); return new Function(args[0], args[1], fbody); }
The crazy function above parses the toString()
of a function into arguments and a function body, wraps them in strings, passes them into a new anonymous function constructor and returns it. It is the inverse function of toString()
.
var g = crazy(f.toString()); g(3,4) === f(3,4); // true g(6,7) === f(6,7); // true
If JavaScript included some higher order functional tools like apply()
, this crazy function could be extended to handle any arbitrary number of function arguments. Fortunately, these tools can be added to JavaScript without too much work.
If anybody has any experience using this feature for anything practical, I'd love to hear about it!
This is, I believe, a textbook perfect example of Greenspun’s 10th Rule 😀
I know that the post is out of date, but i will try anyway. Is there a way to do Build functions from strings in Java? I think that Java 8 lambdas could be useful but i do not know how to use them.
This is JavaScript, not Java, and the code still runs on current browsers.