Jonathan Fischer

It’s the first weekday of summer vacation, and we don’t quite have childcare worked
out yet, so my poor kids are stuck in the office with me this afternoon.

A few things come to mind. First, thank goodness for the Switch. Kayla’s playing Breath
of the Wild quietly. Second, yay, there’s a new Monument Valley out today!
That helps a ton.

Mostly though, I think I need to load up that computer in the background with old Sierra
games. One of my elementary school summers (I think it was between 4th and 5th grade?) I
remember spending a bunch of time at my friend’s dad’s dental office playing
King’s Quest 3 and the Colonel’s Bequest on their computer.

I need to find some good adventure games for the kids. Good ones that take hours and
hours to play though. :D

The Kotlin one takes 1.81 seconds. Tiny bit slower than the Java primitive one, but that’s
probably just due to needing a little more time for Kotlin’s runtime to load. Kotlin does
unboxed primitives properly, yay!

Now I’m curious though: how do the other languages I use on the regular perform? Let’s try
Clojure first, both a straightforward implementation and one tailored to match the Java
one better:

sum-test-straightforward took 5.1 seconds, and sum-test-gofast 1.69 seconds. The gofast
one is comparable to the Java one, probably a little slower: I ran these at a REPL, so there’s
no startup time involved.

Ok, how about Common Lisp? I can think of 3 approaches to take off the top of my head.

SBCL’s sum-test-iterative drops down to 3.13 seconds, still no allocation. No change on
Clozure. I’m probably doing something wrong here, but it’s not clear to me what. The
disassembly of sum-test-iterative on SBCL shows that there’s still an allocation going
on there: maybe the problem is just that 64-bit integers don’t work unboxed due to SBCL’s
pointer tagging?

It turns out, Clang still cheats even if the loop counter comes from outside. I’m pretty
sure it recognized what I’m doing and just turned that loop into Gauss’ trick for computing
an arithmetic series. It doesn’t matter
what loop count I give it, it always takes the same amount of time with optimizations.

I can’t read/write assembly, but playing around on godbolt.org makes
it look like that’s the case: https://godbolt.org/g/FmL66q.
(There’s no loop in the disassembly.) And I can’t figure out how to trick it into not doing
that, so I’ll call it quits for now.

I ended up turning to a Clojure REPL to solve an issue in that project I totally didn’t
sneak Clojure into before and realized I did some things the hard way last time.

First up: you don’t need to create and compile a Java class from Clojure to call into
Clojure code from Java. If I had actually read the Java Interop reference
guide on Clojure.org, I would have noticed that there’s a section on
calling Clojure from Java. It’s much, much easier.

If I define this namespace/function:

(ns project.util)
(defn get-my-thing []
{:my :thing})

I can call it like so:

// In Java code:
// First, find the require function. Then use it to load the project.util namespace
IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("project.util"));
// After project.util is loaded, we can look up the function and call it directly.
IFn getMyThing = Clojure.var("project.util", "get-my-thing");
getMyThing.invoke();

Easy peasy. I don’t have to jump through the gen-class hoops, and bonus! I don’t have to
compile my Clojure code ahead of time. I just need to make sure the source files are on
the class path.

You should of course compile your Clojure code if you’re distributing an application
built on it. It’ll load faster, plus you might not want it readable.

What I specifically didn’t want to hook into that project that I totally wasn’t sneaking
Clojure into is a REPL: I want to be able to poke directly at the application’s state
while it’s running. To do that, I’ll need to make sure that tools.nrepl is
available on the classpath, and require/launch it from within the application.

I could probably use Clojure 1.8’s socket server repl instead, but I plan on using Cider
to talk to it, so nrepl’s a better choice.