Sunday, May 18, 2008

Dynamic Code Reloading in the Scala Interpreter

A week ago I went to the Scala Liftoff Unconference, which was a pretty fun time. At some point I'll write about a conversation I had with Greg Meredith about Bayes and category theory, but only when I understand it all better myself.

The Platinum Sponsor, ZeroTurnaround, gave everyone there a free copy of JavaRebel, which automatically reloads classes on the JVM whenever you change them. No need to restart your java instance. Pretty sweet.

This got me to thinking: one of the things I love about Scala is the interpreter. In particular, one of the greatest advantages of the interpreter is ":load", which just compiles and executes your scala file and let's you play with the results. Unfortunately, the interpreter doesn't work so well when your code base gets over a certain size. But, JavaRebel fixes all that: just recompile your class files in your editor, and JavaRebel will autoreload them! Magic!

Example:

foo.scala:

class Foo {
def bar() = 3;
}


Then, compile it, and open up a modified jrscala interpreter (more on this below):


##########################################################

ZeroTurnaround JavaRebel 1.1
(c) Copyright Webmedia, Ltd, 2007. All rights reserved.

This product is licensed to David Hall

##########################################################

Welcome to Scala version 2.7.1.final (Java HotSpot(TM) Client VM, Java 1.5.0_13).
Type in expressions to have them evaluated.
Type :help for more information.

scala> val f = new Foo
f: Foo = Foo@950feb

scala> f.bar
res0: Int = 3


Now, open back up foo.scala, and change it:

class Foo {
def bar() = 10;
}


Recompile, and go back to your interpreter:


scala> f.bar
f.bar
JavaRebel: Reloading class 'Foo'.
res1: Int = 10

Magic! Ok, so how do I do this? Well, I just made a copy of the scala script (called jrscala) and added two options to the very last line: namely


"-noverify -javaagent:/path/to/your/javarebel.jar":
So it looks like:

${JAVACMD:=java} $JAVA_OPTS -cp "$TOOL_CLASSPATH" -noverify \
-javaagent:/path/to/your/javarebel.jar -Dscala.home="$SCALA_HOME" \
-Denv.classpath="$CLASSPATH" -Denv.emacs="$EMACS" scala.tools.nsc.MainGenericRunner "$@"

And you're done. Obviously I should be more principled/less hacky about it, but it's pretty slick.

Friday, November 16, 2007

Baker's Paradox Revoked

Recently there's been some talk here about Baker's Learnability Paradox, particularly with regards to the Dative Alternation. The paradox is, essentially, that you know the following:
  1. John gave a book to Sue.
    John gave Sue a book.
  2. John donated a book to the library.
    *John donated the Library a book.
(That asterisk means "unacceptable," by the way. If you think it's good, I'd love to hear from you.) However, no one told you that "donate" should behave any differently from "give," yet you know it does. Moreover, there are relatively new words ("text" for SMS) that do undergo the alternation without issue, so it isn't just that you learned only a few verbs undergo dative alternation.

So what's going on? Linguists have spent a lot of time working on this issue, and in some sense this issue is indicative of pretty much all linguistic research: why is it that you can say certain things, and can't say others?

However, in this instance, and in a lot of other instances, I'm not sure there's really a "why" answer here. Instead, I'm coming to believe that we just have heard "donate" many times, almost never in the double object construction, and so we just think we can't say it, because we haven't heard it. It's just like on the one hand we think an arbitrary coin is unbiased, but we also know the sun is going to rise tomorrow: we've never seen it not rise, and we've never seen anything telling us the coin is biased. And sure maybe there's some physics behind the scene that can prove us right, but I'd wager that we can learn arbitrary exceptions (like "donate") without having to worry about Newton's or Kepler's laws.

Sunday, August 19, 2007

Command line arguments considered global

I'm not gonna bother with introductions, yet. I'll see if I like this, and then I'll introduce myself.

On a software project I've recently become involved with, the others involved have this strange love of command line flags. They argue (rightly) that it speeds up their research cycle since they don't have to edit any files or compile before they start another run. This is research code, so keeping the experiment cycle to a minimum is their foremost concern. Alright, that make sense.

However, there's a larger problem: the unfettered use of command line arguments (and, more importantly, a global registry for these flags) gives all the same problems as global variables, and we all know how evil global variables are. Don't believe me? Here's a look at what some code looks like:

class Foo {
private BarFile bar;
public Foo() {
barfile = new BarFile(Args.getCLA("barfile"));
}
}
Ick. Ick. Ick. If you use these, don't write code like that, please. I'll love you forever. Try to allow people some kind of flexibility, or at least... document what flags you use. Prefer something like this:
class Foo {
private BarFile bar;
public Foo(){this(Args.getCLA("barfile"));}
public Foo(String pathToBarFile) {
barfile = new BarFile(Args.getCLA("barfile"));
}
}

That's not too bad, in fact that's down right reasonable. And you're probably saying, "that's not so bad. Just refactor!" Sure. But what if the ctor in question actually makes 3 member function calls before using the CLA. That's no fun to refactor, and it's confusing as hell to figure out where the configuration is coming from. Don't do this, or ninjas will kill kittens or Dijsktra or something.