Editing programs "while they are running"? Why?

I've been getting more into Lisp and Lispy languages lately, and I'm finding them quite powerful.

One thing I've been reading all over the net is that a benefit of writing in Lisp, Clojure, etc, is that you can edit your program "while it's running".

Perhaps I'm missing something, but what is the point?

Sure, it might save a few seconds, but is that all? Whenever I make a change to my program I just stop it then start it again, and that has been working fine for decades.

There must be a reason other than just saving time -- what is it?

Can someone give me a good case study that will make me drool over this feature? :)

Looking forward to drooling!


Solution 1:

There are some extremely cool use cases. One example is in GUI programming - I saw this while developing a GUI app in real time as it was running beside my Emacs: I added code for a new button and hit "C-c C-c" to compile that single function, and the button just appeared in the window! Didn't have to close and reopen the app. Then I began tweaking widgets and manipulating the layout, and the open window would instantly rearrange itself - buttons would move around, new text fields would just pop into being, etc. as soon as I executed each little change I'd made.

Another example is an excellent screencast about the Clojure OpenGL library "Penumbra" where the programmer creates a 3D tetris game in real time. He starts with an empty OpenGL window next to his emacs. He defines a cube object - C-M-x - and it's on the screen. Runs a command to rotate it, immediately it starts spinning. Runs a loop defining 5 more cubes in different locations, pop-pop-pop-pop-pop they appear. It's all immediately responsive, the full OpenGL toolkit right there to play with. Add a new surface texture to your cube and see it appear right away. It becomes a malleable 3d world - the code dynamically modifies the existing world instead of closing and reopening the 3d canvas with every change.

Penumbra Livecoding Screencast - download HD version for best experience.

There is also a great presentation/screencast about the audio library "Overtone" for Clojure. The library is a synthesizer toolkit where you have a set of synth functions to manipulate the soundwave. During the presentation, the developer writes a bit of code that starts a tone playing. He then spends ten seconds writing a loop that plays that sound 10 times but makes the frequency higher each time, and again C-M-x and you hear it, notes ascending higher. Over the space of 20 minutes in real time he gets a song going. It looks like a ton of fun.

Overtone Presentation Link

Other uses would be, for example: Web crawling/data mining - develop and refine algorithms for extracting information in real time, seeing the data returned at each step; Robotics programming - send commands to a robot while it's live; Facial/image recognition - with a library like OpenCV watch your changes instantly update what the library recognizes in an image/video as you're developing the code; Mathematics work (Clojure has "Incanter" for statistics); and any environment where you want to immediately see what effect your changes have had on the data you're working with.

So that's the most fun aspect of having a REPL in front of you. Things that weren't tangible, malleable, interactive, start to be. GUI design, 3D graphics, programmatic sound production, extracting and transforming data, these things normally have been done at arm's length. But with Clojure (and to some extent with other dynamic languages too) it's made to be really tangible and immediate; you see each change as soon as you write the code, and if something doesn't work or you don't get back the result you expected, you just change what you missed and re-execute it immediately.

Clojure is very aligned towards doing this. The wild thing is you can use Java libraries in real-time the same way - despite the fact that Java itself can't! So Overtone is using a Java synth library in realtime despite the fact you never could in Java, Penumbra is using the Java OpenGL bindings, etc. This is because Rich Hickey designed Clojure so it could compile to JVM bytecode on the fly. It's an amazing language - Clojure has made a huge contribution to how incredibly fun and productive programming can be.

Solution 2:

There must be a reason other than just saving time -- what is it?

No, there isn't. I mean, there never is: the whole reason to use a computer at all is to save time. There's nothing a computer can do that you can't do by hand. It just takes a little longer.

In this case, I wouldn't dismiss "a few seconds", given that it's one of the things I do more often than anything else, all day long, for my entire programming career. A few seconds to recompile, a few seconds to re-run, several seconds to recreate the state my program had the previous time -- even on a fast workstation, it can easily be a minute between iterations. (It used to be much worse, but faster hardware has only made it less-awful, not good. Whole-file-or-worse recompiles are I/O-bound, and may never* match the speed of more granular compilation.)

In Lisp, recompiling a single function in an already-running process is almost instantaneous (I've never seen it even 0.1 sec, even on my 5-year-old laptop), and restarts mean I don't have to recreate my state, even when something signals.

Here's a tool that gives me over a 100x speedup of one of the slowest and most common things I do as a programmer. I don't know what else you'd need. We can probably make up some reasons, but if this isn't reason enough I don't know what would be. Um, it's also pretty cool? :-)

(* Whenever somebody says "never" about something involving technology, that person invariably ends up looking like a complete moron 2 years later, and despite Lisp's longevity, I am sure to be no exception.)

Solution 3:

There is a marketing slogan for Lisp:

With Lisp, and its incremental development method, the cost for a change to a software system depends on the size of the change, and not the size of the whole software.

Even if we have a large software system, the cost (time, ...) for a change stays in relation to the size of a change. If we add a new method or change a new method, the effort remains in relation to the effort to edit the method, incrementally compile the the method and incrementally load the method.

In many traditional software environments, the change of a method may need a partial recompilation, a new linked executable, a restart, a reload, etc.. The larger the software is, the longer it takes.

For a human this means, we get possibly out of a state of flow. That's part of the productivity of good Lisp environments: one can make a lot of changes to a software system in a short time, once the programmer feels comfortable and enters this state of flow. I guess many have experienced this, where work gets done in a short time - opposed to times when one sits in front of a system which is unresponsive and we are faced with wait times.

Also there is little cognitive distance between us and the program we are working on. For example if you edit a class in a batch environment, you have to imagine the effect the changes have. In Lisp you edit a class and change at the same time the objects themselves. That means you change the behavior of objects directly - and not a new version of them after a batch edit-compile-link-run-test cycle.

In a Lisp system, you change a class in a CAD system and then it can be immediately active. When people ask, if Lisp works for large software teams, the answer may be that the large software team is not necessary, if you work incrementally. The problem then was/is that really good skilled software developers familiar with incremental development were (are?) rare.

In many applications there is a separate scripting language layer, sometimes for the original developers (and not for users). In Lisp this is not necessary, Lisp is its own extension language.