icosilune

Archive: January 21st, 2009

Metaprogramming

[Experiments,General,Toys] (01.21.09, 10:22 pm)

I am really interested in metaprogramming, writing programs which can modify themselves dynamically. More notably, users of metaprograms will be able to change their functional operation. The advantage of being able to do this is that it enables a great deal of power for development and creating things, but primarily, it’s just a lot of fun. There is something about being able to call functions using reflection that just is really pleasing and entertaining to me.

Most commonly scripting frameworks are used to create secure environments for scripts, and often these scripts will be developed ahead of time, but they also enable a possibility of dynamic scripting, where a scripting environment may be able to do interesting things during run time. Possible examples of run time uses are controlling agents within a world by issuing commands and writing code for an agent’s “brain”, then loading to that into the agent which is live in the world. It would be possible to create a dynamic music or image making program, where the artist can control what is being played or drawn using the scripted code.

With the recent release of Java 1.6, we now have standardized implementation of JSR 223, also known as the scripting framework, which enables some exciting metaprogramming possibilities. This allows one to script on top of Java. So, it would be possible to interact with Python, Ruby, Javascript, or any  other sort of scripting language through this one framework. Interestingly, it is also possible to use Java as a scripting language. Thus, you can script for a Java program… in Java. This may seem ridiculous to some, but I think this is simply delightful.

Here is an example of the scripting framework in use. Note, to actually run this, you must add the java-engine.jar, found in jsr223-engines.zip to the classpath.

package scripttest;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

/**
 *
 * @author Calvin Ashmore
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        ScriptEngineManager mgr = new ScriptEngineManager();

        ScriptEngine scriptEngine = mgr.getEngineByName("java");
        System.out.println(scriptEngine);
        Bindings bindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
        for (Entry<String, Object> entry : bindings.entrySet()) {
            System.out.println("  " + entry);
        }
        System.out.println(scriptEngine.getContext());

        try {
            scriptEngine.put(ScriptEngine.FILENAME, "Toasty.java");
            String script = "public class Toasty {" +
                    "  private float myStuff;" +
                    "  public Toasty(float stuff) {" +
                    "    myStuff = stuff;" +
                    "  }" +
                    "  public String toString() {" +
                    "    return \"I have a thingy! \"+myStuff;" +
                    "  }" +
                    "  public int performWombat(String theWombat, float multiplier) {" +
                    "    int toast = Integer.valueOf(theWombat);" +
                    "    float thingy = toast * multiplier;" +
                    "    double d = Math.sqrt(1 + thingy*thingy);" +
                    "    return (int) d;" +
                    "  }" +
                    "}";

            Class toastyClass = (Class) scriptEngine.eval(script);
            Constructor c = toastyClass.getConstructor(float.class);
            Method m = toastyClass.getMethod("performWombat", String.class, float.class);

            Object toasty = c.newInstance(1.0f);
            System.out.println("My toasty: " + toasty);

            System.out.println("This will work:");
            System.out.println("result: " + m.invoke(toasty, "234", 1.23f));

            System.out.println("This will not:");
            System.out.println("result: " + m.invoke(toasty, "eek", 1.23f));

        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

(Apologies for the strange variable names) It generates the output:

com.sun.script.java.JavaScriptEngine@1abc7b9
javax.script.SimpleScriptContext@c55e36
My toasty: I have a thingy! 1.0
This will work:
result: 287
This will not:
Jan 21, 2009 9:27:15 PM scripttest.Main main
SEVERE: null
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at scripttest.Main.main(Main.java:70)
Caused by: java.lang.NumberFormatException: For input string: "eek"
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
        at java.lang.Integer.parseInt(Integer.java:447)
        at java.lang.Integer.valueOf(Integer.java:553)
        at Toasty.performWombat(Unknown Source)
        ... 5 more

This example is able to instantiate and call methods on a simple object effectively. However, in order to do the more interesting things described above, we need to make use of interfaces. So, the scripted class will implement an interface defined by the main program. That interface will define the contract for operation. So, instead of using reflection to call methods, we can simply cast the object to belong to the interface and call the methods directly. I’m not going to write this yet, but maybe soon.

A Kindred Academic

[General] (01.21.09, 3:04 pm)

Evidently, I’m not the only one who is interested in models and worlds and values. I was referred to Matthew Kirschenbaum‘s essay “Hello Worlds“. This was interesting because he not only references the work of Ian Bogost and Michael Mateas, but he frames the discussion as an application of digital humanities, to think about worlds and as the material content of both literature and games. He also mentions, however briefly, Jane Austen. Austen is inescapable, an inevitable fact underneath everything, a humming constant beneath the universe. All roads lead to Jane Austen. I don’t know whether to be pleased or frightened.

This is Encouraging

[General] (01.21.09, 8:50 am)

It is encouraging to read that my game design ideas are interesting to some people! He is not the first person to suggest the idea of a Jane Austen Pride and Prejudice Game, though. I don’t have links for some of the others, but there is clearly a demand for this kind of thing. I am not sure if the project that I am working on is exactly similar to what they have in mind, but there is a chance that it will fill the role.

Later today I am intending on posting a text analysis, and hopefully hopefully both of the papers that I have been working on. We’ll see how that goes.