I read online that Clojure uses the ASM library to generate JVM Bytecode, I also saw that Clojure has a REPL.
I assume each line of code executed by the REPL is compiled into a Java class using ASM and then that class is loaded to execute the code. If this is the case then each line would cause a new class file to be generated, so I'm not sure how local variables declared on one line could be shared with the lines which follow in the REPL.
Does anyone know how Clojure's REPL works? I tried reading the Clojure source code but I don't know much Clojure.
It's not "each line" that is compiled at a time, but "each form".
In the REPL, you are always in some namespace. You can change the current namespace of a REPL by using in-ns
. In each namespace, there is a binding between symbols (loosely, "names") and Vars (loosely, a container that holds an immutable value). The "state" of the namespace is in the bindings of that namespace.
For example, if you evaluate the form (def a 17)
in the current namespace, that will create a new (if it does not already exist) binding for the name a
that points to a Var
that contains the value 17
. Now, you could later evaluate the form (+ a 25)
in the same namespace. That will get the value of a
in the namespace and add that to 25 to return 42.
The above is for symbols that are local to the namespace. These symbols are available to all forms evaluated in that namespace. (They also can be accessed from other namespaces, but I'll leave that out for now).
You might take a look at https://clojure.org/reference/evaluation if you have not already. The article at https://clojure.org/reference/vars might also be helpful.