What is the difference between Clojure REPL and Scala REPL?

I have been working with the Scala language for several months, and Ive already created a couple of projects in Scala. Ive found that the Scala REPL (at least its IntelliJ Worksheet implementation) is quite convenient for rapid development. I can write the code, see what it does, and its nice. But I perform the procedure only for functions (not the whole program). I can not start my application and change it in place. Or at least I donโ€™t know how (so if you know that you can give me advice).

A few days ago, my associate told me about the Clojure REPL. He uses Emacs for the development process, and he can change the code in place and see the results without restarting. For example, it starts this process and, if it changes the implementation of a function, its code will change its behavior without rebooting. I would like to have the same with the Scala language.

PS I do not want to discuss either the language that is better, or functional programming is better than object-oriented. I want to find a good solution. If Clojure is the best language for the task, let it be.

+6
source share
1 answer

The short answer is that Clojure was designed to use a very simple one-pass compiler that simultaneously reads and compiles a single s-expression or form. For better or worse, there is no global type information, no global type inference, and no global analysis or optimization. Clojure uses instances of clojure.lang.Var to create global bindings through a series of hash maps from text characters to transactional values. def forms all the bindings in the global scope in this global binding map. So, where in Scala a โ€œfunctionโ€ (method) will be allowed for an instance or static method for a given JVM class, in Clojure a โ€œfunctionโ€ (def) is actually just a reference to an entry in the variable binding table. When a function is called, there is no static reference to another class, instead var is a reference by symbolic name, and then dereferenced to get an instance of the clojure.lang.IFn object, which is then called.

This layer of indirection means that you can reevaluate only one definition at a time, and this reevaluation becomes global visible to all clients of the redefined var.

In comparison, when the definition in Scala changes, scalac must reload the modified file, macro, type infer, type checking, and compilation. Then, due to the semantics of loading classes on the JVM, scalac must also reload all classes that depend on the methods in the class that has changed. Also, all values โ€‹โ€‹that are instances of the changed class become garbage.

Both approaches have their strengths and weaknesses. Obviously, the Clojure approach is easier to implement, however, it pays a constant cost in terms of performance due to the constant function search operations, forgetting about the correctness problems due to the lack of static types and what you have. This may be suitable for contexts in which many changes occur at short intervals (interactive development), but less suitable for contexts where the code is mostly static (deployment, therefore, Oxcart). some work that I did suggests that the slowdown in Clojure programs due to the lack of binding of the static method is about 16-25%. This does not mean that Clojure slow or Scala is fast, they just have different priorities.

Scala decides to do more work from the front, so that the compiled application will work better, which may be more suitable for deploying the application with a slight reboot or without rebooting, but will prove drag and drop if you want to make a lot of small changes.

Some of the materials I have on hand about compiling Clojure code is more or less cronological in publication order, since Nicholas influenced my GSoC work.

Which, I suppose, leaves me in an unfortunate place, simply saying: "Sorry, Scala was not intended for this, as Clojure was" in relation to hot-swapping code.

+18
source

Source: https://habr.com/ru/post/979364/


All Articles