[HN Gopher] OpenLDK: A Java JIT compiler and runtime in Common Lisp
       ___________________________________________________________________
        
       OpenLDK: A Java JIT compiler and runtime in Common Lisp
        
       Author : varjag
       Score  : 102 points
       Date   : 2025-02-05 12:17 UTC (1 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | atgreen wrote:
       | Hello -- I wrote this! It's still very much a work in progress.
        
         | whalesalad wrote:
         | A pragmatist will point to this and say, why not Clojure? Can
         | you share more about what keeps you using SBCL instead of
         | Clojure?
        
           | jhbadger wrote:
           | Or for that matter, Armed Bear Common Lisp (real CL
           | implemented in the JVM rather than Clojure which is more like
           | Scheme mixed with its own ideas). Still, it's a neat trick,
           | running Java classes on a Lisp that isn't in the JVM itself.
        
           | remexre wrote:
           | I thought Clojure already had JVM interop?
        
             | codr7 wrote:
             | Clojure runs on the JVM; this is the opposite, Java in a CL
             | compiler.
             | 
             | Besides, there's more to Lisp than Clojure.
        
           | eadmund wrote:
           | Well, for one thing Clojure is not Lisp. It's a neat language
           | (and is informed by experiences with Lisp), but it's a
           | different thing.
        
             | jgalt212 wrote:
             | What's the biggest thing your mind that makes Clojure not
             | Lisp?
        
           | atgreen wrote:
           | I'm sure they would, but I have the freedom to not be
           | practical! The journey is the destination.
           | 
           | Common Lisp is fun to code in, and the tooling is top-tier.
        
             | sushidev wrote:
             | Could you share some of what is great about the cl/sbcl
             | tooling?
        
               | atgreen wrote:
               | If you are writing services for a platform like
               | kubernetes, the inner-loop development cycle is
               | unmatched. You just connect your editor to the lisp image
               | running in k8s, and with a couple of keystrokes, your
               | code changes are shipped to the target container,
               | replacing what's running live -- as native machine code.
               | You can debug in a repl, handle conditions (exceptions)
               | interactively with restarts, etc etc.
        
           | koito17 wrote:
           | > why not Clojure?
           | 
           | Common Lisp implementations like SBCL have static typing,
           | performance, instant (and effortless) compilation to native
           | machine code, and so on. No need to deal with Leiningen or
           | copy-pasting a deps.edn / build.clj template across projects.
           | If I want to experiment with SIMD intrinsics with the comfort
           | of a REPL, I can't do that with Clojure, but I can do that
           | with SBCL and a built-in library (SB-SIMD).
           | 
           | Note: I have used Clojure professionally and still use it for
           | some personal projects, but I try to be aware of the trade-
           | offs when deciding to use Clojure / Common Lisp / any other
           | programming language.
        
             | whalesalad wrote:
             | do you have any reference libraries/apps/projects you could
             | refer me to? curious to see what a healthy and idiomatic
             | project looks like.
        
         | hencq wrote:
         | Very cool! I'm curious whether you're using it (or planning to
         | use it) yourself for anything serious or if it's just to see if
         | it could be done. Are you planning to support classes beyond
         | Java 8 at some point?
        
           | atgreen wrote:
           | I'll definitely use it when it becomes usable. And, yes, it
           | needs to support newer versions of Java. Crawl.. walk.. run.
           | But you are right.. part of my motivation was just to see if
           | it was possible. Many years ago, I worked on gcj, which was
           | similar in concept, except that it mapped Java classes to C++
           | classes (as implemented by g++). I've been on a Common Lisp
           | kick for the past few years, so it seemed like a fun
           | challenge. The fact that the OpenJDK class libraries are free
           | software now makes this more practical.
        
         | skapadia wrote:
         | @atgreen - Would love to hear what key lessons / takeaways
         | you've learned while working on this project?
        
       | rootnod3 wrote:
       | Finally I can run Clojure in Common Lisp :D
       | 
       | Joke aside, that is an amazing project.
        
         | blu3h4t wrote:
         | Does this have something to do with recursion? I guess what I'm
         | thinking is bout is inception, I guess there already exist some
         | lib called inception, wonder what it would do, a compiler? :D
         | Java to cl compiler I guess :D
        
       | anonzzzies wrote:
       | Nice work. I will have a read of the code over the weekend.
        
       | behnamoh wrote:
       | Speaking of Lisp, I'm developing a programming language that is
       | similar to other Lisps, but I noticed that we can sprinkle a lot
       | of macros in the core library to reduce the number of parentheses
       | that we use in the language.
       | 
       | example: we could have a `case` that works as follows and adheres
       | to Scheme/Lisp style (using parentheses to clearly specify
       | blocks):                   (case name             (is_string?
       | (print name))             (#t         (print "error - name must
       | be a string"))         )
       | 
       | OR we could also have a "convention" and treat test-conseq pairs
       | implicitly, and save a few parentheses:                   (case
       | name             is_string?    (print name)             #t
       | (print "error ...")         )
       | 
       | what do you think about this? obviously we can implement this as
       | a macro, but I'm wondering why this style hasn't caught on in the
       | Lisp community.
       | 
       | Notice that I'm not saying we should use indentation--that part
       | is just cosmetics. in the code block above, we simply parse case
       | as an expression with a scrutinee followed by an even number of
       | expressions.
       | 
       | Alternatively, one might use a "do" notation to avoid using
       | (do/begin/prog ...) blocks and use a couple more parentheses:
       | (for my_list i do             (logic)             (more logic)
       | (yet more logic)         )
       | 
       | again, we simply look for a "do" keyword (can even say it should
       | be ":do") and run every expression after it sequentially.
        
         | hencq wrote:
         | A bunch of lisps do that. Clojure for instance or arc use
         | conventions like that to reduce the number of parentheses.
         | 
         | See e.g. cond in clojure:
         | https://clojuredocs.org/clojure.core/cond
        
           | diggan wrote:
           | > Clojure for instance or arc use conventions like that to
           | reduce the number of parentheses
           | 
           | Clojure also reduces parentheses by introducing more
           | characters for various data-structures (good and bad, many
           | would say), like [] for vectors, which are for example used
           | for arguments when defining functions                   (def
           | add-five [a]           (+ a 5))
        
         | shawn_w wrote:
         | Your for example is basically Common Lisp's `loop`
         | (loop for i in my-list           do (logic)              (more
         | logic)              (yet more logic))
        
         | kgeist wrote:
         | In an old programming language project of mine, I wanted to use
         | something similar to S-expressions for most of the grammar
         | because they are very universal and flexible, but I didn't like
         | having too many parentheses, so I extended the syntax by
         | allowing semicolons as an alternative.
         | 
         | So, in pseudocode:                 (print (+ 1 2))       (exit
         | 1)
         | 
         | becomes:                 print (1 + 2); // "+" is the 2nd place
         | because it's a method call on "1"       exit 1;
         | 
         | Both variants are valid; semicolons are just syntactic sugar to
         | reduce the number of parentheses. In the AST, they represent
         | the exact same expressions.
         | 
         | For function bodies, I also introduced an extension to make
         | lambdas stand out more from the rest of the code by using curly
         | braces:                 (0 to 10) loop ^(i) {         print i;
         | // Internally transformed to (print i)       }            //
         | clarification:       // 1. The "to" method of the 0 object
         | creates a Range object, which has a "loop" method that accepts
         | a lambda.       // 2. The ^ symbol is just a shorthand for
         | "lambda".
         | 
         | As you can see, this wasn't a Lisp dialect (and I'm no expert
         | at Lisps), but I liked the idea of having a universal
         | expression structure in the AST, however I eventually ended up
         | extending it with two additional modifications that made it
         | more readable (at least for me)
        
         | tmtvl wrote:
         | Imagine if we had a Lisp with proper types, we could do
         | something like...                 (typecase name
         | (String (print name))         (otherwise (print "error: name
         | must be a string!")))
         | 
         | And if that Lisp had some kind of Object System, we may even go
         | further and have stuff like...                 (defmethod
         | namecall ((name String))         (print name))
         | (defmethod namecall ((name Number))         (print "I am not a
         | number, I am a free man!"))
        
           | codr7 wrote:
           | Wild!
        
           | behnamoh wrote:
           | clojure's multi-arity addresses this to some extent but
           | pattern matching like we know it in Haskell is very weak in
           | Lisps...
        
       | svilen_dobrev wrote:
       | pff. Now run a hardware Lisp machine under it..
       | 
       | https://en.wikipedia.org/wiki/Lisp_machine
        
       | cduzz wrote:
       | Have you seen:
       | 
       | https://winworldpc.com/product/ibm-visualage-for-java/10
       | 
       | QUOTE: VisualAge for Java is based on an extended Smalltalk
       | virtual machine which executes both Smalltalk and Java byte
       | codes. Java natives were actually implemented in Smalltalk. Later
       | versions were implemented on regular Java.
       | 
       | Obviously not the same....
        
         | atgreen wrote:
         | Yes, I'm familiar with that! It was created by the OTI team in
         | Canada, which was acquired by IBM. I think some of them are
         | still around, working on IBM's OpenJ9 java implementation. They
         | reach out to me now and then on libffi-related issues.
        
       | hondadriver wrote:
       | Reminds me of Greenspun's tenth rule of programming (also counts
       | for Java, but this most probably predates it):
       | 
       | Any sufficiently complicated C or Fortran program contains an ad
       | hoc, informally-specified, bug-ridden, slow implementation of
       | half of Common Lisp.
       | 
       | https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule
        
         | mjburgess wrote:
         | Ritchie's Revenge: And this half is still faster than Common
         | Lisp.
        
       ___________________________________________________________________
       (page generated 2025-02-06 23:00 UTC)