Hacker News new | ask | show | jobs
by jonathankoren 1682 days ago
REPLs are great, and I always prefer a language with one than one that doesn’t, but being able to patch a running system is Lisp’s killer feature in my opinion. I’ve never seen another language that support that.

I had a bug in a long running program that would only show up after like six hours. I couldn’t replicate it in isolation because it had something to do with how state was being maintained. I set a conditional breakpoint right before the crash, inspected the stack, patch the function, and then had it pick back up by reëvaluating the current function call.

Damn thing just worked. It was amazing, and saved me so much time.

6 comments

Smalltalk is designed around this functionality. In fact the whole Smalltalk system is a live instance that has been modified like that since development started.
Smalltalk is seriously awesome. I think it has a slight advantage over lisp in its fix-the-airplane-while-it-is-flying-at-3000 feet property.
How are the two not exactly the same in that respect?
Python programmer not accustomed to a "real" REPL. My closest experience would be Jupyter notebooks, where dangling state is more a liability than an asset.

> ...inspected the stack, patch the function, and then had it pick back up...

After you edit the live state of the program, how do you translate that into code sitting in source control? Do you save this blob of memory and pass that down through generations?

1. Stop the system.

2. Modify the source code containing the function.

2a. Save the file.

3. Copy function definition to the debugger’s repl, and evaluate it.

4. Resume the system from frame that calls the function.

But yes, you must be diligent about making sure the source files contain the code that is actually running, but that’s not much different than artifact tracking.

Usually one wants to make the change persistent in the sources.

Step a): One just evaluates from the sources, while changing them. Once done -> save sources.

Step b): Create a patch file, which changes the image. Such a patch file can be loaded while starting an image, until one decides to save a new image with the changes already loaded.

For example there is a new release for the commercial LispWorks IDE once every one or two years. Users usually get only patch files for bug fixes during the one or two years maintenance. Thus I have a directory for patches to LispWorks, which are loaded when I start the base image.

One way would be to make the change in the source file and then recompile/reload that one function. This is pretty easy to do with SLIME; you can highlight the snippet of code you want to evaluate, and then send that to your program to be evaluated on-the-fly.
This is one of the fundamental features of the BEAM (the Erlang/Elixir virtual machine) as well.
Almost all Smalltalks, especially the image based ones support dynamic run-time patches.
Where would you recommend getting started with Smalltalk on Linux today?
Squeak or Pharo if you want the full image-based experience. Some distros come with Squeak but the packaging can be confused and the versions are often old. A slow and slightly janky but surprisingly useable Squeak experience can be had in a web browser at https://squeak.js.org/run/ . Older Squeak versions tend to run faster in SqueakJS.

There are tutorials all over the place however as Smalltalk is a system that, like Lisp, has dialects, they tend to be system specific. Lots of material at http://stephane.ducasse.free.fr/FreeBooks.html .

jdougan already mentioned Pharo. There's a MOOC here : https://mooc.pharo.org/
FORTH (indirect threaded implementations at least) allows to redefine words while the system is running (fingers crossed).

Just because that feature is available and at one time was desirable (when machines were so slow, that compiling would break the flow), doesn't mean one needs to or should use it today.

Compiling can certainly still break the flow depending on the language and size of the project. Just ask Google.
I believe .NET 6 allows hot reloading, and Erlang already has that feature too