Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I should have gone into more detail for sure.

The problems with the JVM are more cultural or political and not necessarily technical, although at the time clojure on the jvm did require quite a bit of memory and the cold startup times weren’t great for a simple, “watch this file in development and restart the server” workflow.



> “watch this file in development and restart the server” workflow

Fortunately, no one in the Clojure ecosystem works like that, thanks to the REPL :) You fire up the server, send code straight from the editor to the server and evaluate everything on the fly, no restarts needed.


Yes the repl was one of clojure’s strong points, definitely, but I would argue that a fast restart + logging + irb gets you most of the way there


Hmm, not sure about that. Consider the following (very simplified) example:

    (defonce current-count (atom 0))
    
    (defn handle-request [req]
      (swap! current-count inc)
      (str "Hello " (-> req :params :name) @current-count))
    
    (run-server handle-request :port 8080)
If you do the whole "restart server" process every time you change `handle-request`, you lose the state of `current-count`, but if you instead just change the function and "send" the new one to a already running server, the state of `current-count` is still the same, even when the new function definition is being used.

Now imagine it with more complex state, or with things that require multiple states to do something. Reloading the server each time would mean you have to manipulate the state into the right "shape" each time before you can test your change, while if you can retain your state even after changing the code, you'd avoid that.

This is why I'm still stuck in Clojure and unable to go back to writing code in other languages. The productivity gain is simply too high to throw away by not using Clojure (or other languages that are driven by the same ideas).


Both the .Net Runtime and the JVM provide this functionality for all the languages they support ... I mean it requires a bit of work for the languages to acctually enable this in a proper workflow, but C#, Java, Kotlin, Visual Basic, ... all support this (which I must say makes even testing a joy. Test not succeeding? Step through and if something goes wrong, just change the code, press F8 and it restarts at the function call or sometimes even the basic block you changed) I believe Visual Studio supports this even for a C++ without a .Net Runtime.

Microsoft calls it "edit and continue". Not sure what Oracle/IBM calls it but it works.

It's not guaranteed to work and there's edge cases where it silently corrupts stuff. Function pointers of course don't update, for example. The Clojure way is cleaner.

https://docs.microsoft.com/en-us/visualstudio/debugger/how-t...

https://dzone.com/articles/hot-swap-java-bytecode-on-runtime

There have been tech demos showing that LLVM can do this for C++ compiled to machine code. I don't know if it's really working anywhere, but it certainly can be made to work if someone puts in enough effort.

I once actually established a debugging connection from eclipse to a telephony server running on JVM that was actually serving calls and live-replaced the dialplan handling code, stopping a ddos without making things worse. It even works for that case. Not something I'd advise doing, but I love that this can actually work ...


Sounds like live patching in Erlang. Kudos for pulling it off without support by the runtime.

https://www.youtube.com/watch?v=BXmOlCy0oBM


I has been superseded by Hot Reload on Visual Studio, and in both ways, C++ is also supported.


Sucks you can't use it in VS Code ...


If your long term state depends upon ephemeral, non-persisted, data then you're hosed if you ever have to restart anyways. If anything brings that server down, you lose current-count as well, whether it's to change out the definition of handle-request or a power outage. So current-count must not be a useful (long term) value worth persisting or the above program is broken from the start.

In the former case (it's useless) the stop-the-world-and-restart approach doesn't hurt anything, in the latter you would need to fix the program anyways.


Yeah, I mean, obviously atoms are not used for long term state storage, I'm not suggesting your replace your database with a atom. But it's useful for a lot of things that are not needed for long-term storage. And even more importantly, it demonstrates the example of how you can use the stateful repl to avoid restarting the full server on every change and still keep state around.


That is true, getting back to the same state in other languages is usually done with unit/integration tests, definitely not as nice as the repl.

Although it is nice to have them written down and more explicit


Why shoot for "most of the way there" when one of the core features of the language is "all the way there"?


The downsides of clojure on the jvm which I had kind of forgotten about until today like long stack traces and using a lot of memory kind of outweigh the upside of the repl




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: