5 ms·
Good article. He missed out the main pro though (and literally the only reason I ever use any Lisp): hot swapping. The ability to change code on the fly as the
by hacker_9 9y ago
Good article. He missed out the main pro though (and literally the only reason I ever use any Lisp): hot swapping. The ability to change code on the fly as the program is running. For this to actually work you need 2 things:
1. No explicit types: Everything in Clojure is just a list or hash map, so I can add extra members to anything at runtime no problem. The amount of static checks Rust does at compile time makes this non viable.
2. Fully immutable data structures: If my changes cause exceptions, then the program can just rewind and throw away the new state it was building, let me fix the error I made, and then continue on as if I never committed the broken code. In Rust an exception would mean I've potentially mutated state in a bunch of places, and now can't get back to the previous working state at all.
- MichaelGG 9y agoIn which scenarios do you use hot swapping?
- hacker_9 9y agoJust about every scenario? Any algorithm I am working on, any function, any config variable I want to tweak in real time, any GUI I am developing, and so on.
- MichaelGG 9y agoSo for interactive work? Versus updating long running server jobs? I'm used to using the REPL in F#, but you can't redefine data types and have old code pick up on it - only new code. Such an approach is theoretically possible in Rust. Debuggers can do this for C++ to some extent.
- stingraycharles 9y agoClojure has a very REPL-driven workflow, where you connect your editor to a REPL (usually emacs+cider) and get instant feedback about anything, reload code on the fly, and inspect your program's state. This is a fundamental concept of pretty much any LISP, and is lacking in rust.
- nonsince 9y agoYou don't need dynamic types to allow hot reloading, as long as a function has the same absolute path and type signature it can be done. I'm pretty sure miri[0] plus some compiler hooks would allow this, although it would need to reach nearly speed-parity with debug code if not release code. Hot reloading and/or repl-driven development is my number one programming desire right now, and Rust is my most-used language, so this would be life-changing for me. Also, Scheme and CL allow free reign on data mutation and RDD/HS work fantastically in them [0]: https://github.com/solson/miri https://github.com/solson/miri
- hacker_9 9y agoI didn't say it wasn't possible, but I've found that hot-swapping in languages that use mutable data structures, and have heavy type systems, makes for a poor experience. If I can constantly cripple the runtime with hot-swapping, or I can't change any type definitions, then there is little point to it.
- yomly 9y agoTyped/racket supports hot swapping to a similar degree as clojure
- elcritch 9y agoFollowing on this, it should be possible to use something like CLASP [1] to do hot loading on C++ code objects. https://github.com/drmeister/clasp https://github.com/drmeister/clasp
- _asummers 9y agoThe BEAM and particularly Elixir satisfy all of the above., 0 is supported in the VM by releases, though admittedly probably not to your satisfaction. 1 is true in Elixir. Structs are just maps with a __struct__ key under the hood, though you can't arbitrarily add things here. I think this is true with defstruct in clojure, as well. 2 is true in Elixir, except via message passing between lightweight processes, which then return NEW state (of any shape) representing their current state at the end when you invoke their functions. And we have hygienic macros =)
- steinuil 9y agoEven C can do hot swapping using shared libraries, and it has none of those features.
- iopq 9y agoI've seen a guy change some code for shaders, go into another tab and that tab already had the new changes after the compile. If you can do this in C++, then surely you can do stuff like this for Rust. You can certainly have a hash map of trait objects in Rust (it just points to the vtable and the data). This means anything that has an impl for the Trait can be stored in the hash map. Rust also doesn't have exceptions, using algebraic data types to hold on to the errors and return them up the stack. Because it's on the stack, it's not some global state that's mutated, but we just went back to the calling function and we can attempt to try again.