(Yet Another) Lisp in Go
johnj.com
johnj.com
Rather than bias the results this way, much more interesting would be to test what the speeds are (1) after the VMs have launched, and also (2) when the VMs are hot, that is, Java has compiled your Lisp classes.
It's not since startup time matters for CLI applications.
Not if you compare to AOT for languages who lack garbage collectors. C, C++, Fortran would still be quite faster.
Of course, Java also has a lot of overhead from the language and implementation level, because of things like no generic lists of integers, no struct embedding leading to lots of pointer-chasing, a tendency for over-allocation, and direct overhead of the advanced JIT itself - performance counters, dummy instructions to support de/re-optimizations on the fly etc.
Basically what you're suggesting would be the absolute best-case for JIT.
Can you link to something or explain how to use JIT caches?
https://docs.oracle.com/en/java/javase/18/vm/class-data-shar...
Or how to use it alongside Spring,
https://medium.com/@toparvion/appcds-for-spring-boot-applica...
For OpenJ9,
https://developer.ibm.com/articles/optimize-jvm-startup-with...
On Android, ART does it automatically since Android 7,
import java.math.BigInteger;
public class Fact {
public static BigInteger fact(BigInteger n) {
if (n.equals(BigInteger.valueOf(1))) {
return BigInteger.valueOf(1);
} else {
return n.multiply(fact(n.subtract(BigInteger.valueOf(1))));
}
}
public static void main(String args[]) {
System.out.println(fact(BigInteger.valueOf(100)));
}
}
With OpenJDK 11.0.14, `time java Fact.java` gives real/user/sys of 0.267s/0.654s/0.033s. But that's not compiling the file first which some programmers aren't even aware is a thing Java can do now, if I do the usual thing of compiling with javac then on the class file `time java Fact` I instead get 0.050s/0.043s/0.010s. For Clojure, `time java -jar /usr/share/clojure-1.10/lib/clojure.jar fact.clj` gives 0.468s/1.069s/0.056s.Edit: for fun since the author mentioned Common Lisp, `time sbcl --no-sysinit --no-userinit --script fact.lisp` gives 0.005s/0.003s/0.002s. If I make a binary out of this instead, `time ./fact` gives 0.003s/0.002s/0.001s`. Since even a time of an empty C program's a.out can sometimes give numbers like 0.001s/0.000s/0.001s I'm clearly running into precision limits of the time command. (CL itself has a time macro that will helpfully give you a processor cycles count, about 290,000 on my machine for this.) I think the author is overestimating the difficulty of adding features to Common Lisp relative to what they plan to do with this toy; CL for scripting works great too.
For Java 11, the docs are on https://docs.oracle.com/en/java/javase/11/vm/class-data-shar...
Latest versions have other improvements like PGO info as well.
More specifically, Clojure —
https://stuartsierra.com/2019/12/21/clojure-start-time-in-20...
"Fission" better than "splitting" surely? ;)
I can identify having this impulse after doing things with Rust but fantasizing about a LISP cousin: Smalltalk.
Now that you mentioned Go it is a more natural thing to try due to its garbage collection already done there. Thanks por pointing that out.
What restrains me a bit of starting any effort in this direction is Pharo's current performance:
Time microsecondsToRun: [ 100 factorial ].
"86"Said that, I do not want to sunk time into trying to improve something, only to find out tha it will perform worst.
Maybe the compromise is to try to do a minimal proof of concept only manually transpilig a couple of objects from Smaltalk to Go and measure that?
In any case, shouldn't your measurement be made the same way John Jacobsen seems to have made measurements —
$ time ./bin/visual ./image/visualnc64.im -nogui -doit "Stdout nextPutAll: 100 factorial printString; cr. ObjectMemory quit"
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
real 0m0.616s
user 0m0.452s
sys 0m0.161sBy the way, I'm not recognizing that command, I'm curious, what smalltalk is that you're using there?
I don't think we know about the hardware used for the other measurements — so sketchy comparison.
> … excluding system startup/shutdown…
Why would you do that when the other measurements included startup/shutdown?
https://github.com/eigenhombre/l1/
> … not recognizing that command…
Cincom Smalltalk, VisualWorks® 8.3 run with `time` from a terminal window command line, like the other measurements.
$ cat fact.st
Stdio stdout
nextPutAll: 100 factorial printString;
nextPut: Character lf.!
SmalltalkImage current snapshot: false andQuit: true!
$ time bin/pharo --headless Pharo10-SNAPSHOT-64bit-502addc.image fact.st
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
real 0m0.350s
user 0m0.303s
sys 0m0.049sJava exists today in many places where change codebase is a nightmare and keep up software is no less a nightmare so having a more manageable language able to insert itself in the old ecosystem is valuable, but on a moderately new language with nothing so big to be in a state of needing a nightmarish replacement why?
It's like Hy for Python: it's nice, a programming exercise but for what more than the technical piece? How many Python programs need a new language while remain on their own python VM? How many Python programmers want lisp with Python underneath?
Please try with the latest 0.8.2:
$ time bb /tmp/fact.clj
bb /tmp/fact.clj 0.02s user 0.01s system 90% cpu 0.035 total
Wrapping the last expression with `(time ...)` yields: 0.285566 ms
It also generally speaking doesn't have an intermediate representation that you could target directly, because it does a lot of optimization directly on the GO AST. Though you might be able to have a different language compile to its SSA directly, but it would not be easy at all.
The GO runtime also doesn't allow for any dynamic code loading, so you wouldn't be able to have a REPL.
Is this true?
I'm guessing that various incarnations of the Scheme language may be most compatible and interchangeable.