I’m writing a bunch of Scheme benchmarks in F#. The N-Queens problem is determining how to place 8 queens on an 8×8 chess board so all are safe. Computing all 92 possibilities does a fair amount of recursive function calls and list processing. To do this 2000 times with F# takes about 17 seconds. For comparison, it takes 26 seconds with Scheme48 (a Scheme interpreter). Compiled implementations of Scheme can solve this problem in 2 to 3 seconds. Why is F# only 2X faster than Scheme48? I’ll report the rest of the benchmarks later.
A language that properly supports modularity must deal with name collisions. In C# 3.0, extension methods allow us to dynamically add new methods to another class. So what happens when methods collide? If I add the same method signature (name + parameters) to a class, what will the compiler do?
- If I include two different namespaces, and both add the same method, the compiler warns that my method call is ambiguous. That’s good. But how can I explicitly specify which method I want?
- If the method exists in another namespace and I add the same method, the compiler does not report that I’ve modified an existing method. This means my program could change if anyone working in the same namespace accidently modifies another method. The compiler should warn that I’ve changed an existing method.
It should be possible to write a language interpreter on top of Java or .NET and rely on method inlining to instantly get compiled code. Implement most of your interpreter opcodes as small static methods: Add, Subtract, LessThan, etc. Translate your language into Java/C# methods that call these opcodes. When the JIT sees all these small static methods, it should inline and optimize them. Presto! You’ve just written a compiler. It’s a bit like using partial evaluation to generate a compiler from an interpreter. I think Peter Sestof did this the hard way a long time ago.