Static entities such as classes and methods (and depending on your Smalltalk implementation namespaces and object versions) can be modified at runtime, i.e. while your program is running you can make a change and get an immediate effect. This is now known as "live" programming, however, it is notably different from your typical "hot reload" implementation in that it knows how to apply changes for individual code entities. E.g. if you modify a method you don't need to reload the entire class or module or entire runtime. For me, this feature alone makes for a big productivity increase.
Dynamic entities such as stack frames can also be reified by the meta interface. This allows to inspect and modify runtime processes, e.g. inside a "debugger" [3]. Note that the debugger allows to modify and create new code while your are debugging. This is a powerful feature because it means that you get access to runtime objects inside of it. Ever wondered what object gets passed into your method at a certain point, what methods it knows, what properties it has? Just try it out and see for yourself!
An interesting analogy to describe this experience: [4].
For a deeper description about the ideas behind that see Design Principles Behind Smalltalk [5].
Also, most Lisp implementations provide the same kind of meta interface, and CLOS arguably provides a more flexible and higher level abstraction of these ideas [6].
As for similar environments I have worked on, there is Lively for JavaScript [7] and cloxp for Clojure [8]
[1] http://sdmeta.gforge.inria.fr/FreeBooks/ByExample/31%20-%20C...
[2] Chapters 16 http://stephane.ducasse.free.fr/FreeBooks/BlueBook/Bluebook....
[3] https://www.youtube.com/watch?v=1kuoS796vNw
[4] http://simberon.blogspot.nl/2013/01/swimming-with-fish.html
[5] https://www.cs.virginia.edu/~evans/cs655/readings/smalltalk....
Then it's not static.
What's with kids again not knowing basic computer science?
Another thing you can do that isn't explicitly mentioned above is "dropToFrame" where you can point to any one of the calling methods out of the call stack and have the process revert to a state so it is like it only just entered that method. I occasionally have debugged bugs that only surfaced rarely simply by having a tester call me when the problem manifests, and I spent a few hours with that function call live, repeatedly taking runs through to see what happened then reverting to a state where the problem was about to manifest but not so early that everything was lost.
You can also write debugging code of arbitrary complexity. You could write a 20-line query to do consistency checking of some data structure that is being operated on to satisfy yourself of various things you assume are true. You can make a special debugging subclass of some ubiquitous class, tell one particular instance of the class to become of the subclasses type which will then do all sorts of extra bookkeeping (perhaps recording stack frames every time it is invoked to see who asks it to do things).
You can execute a windowUnderMouse call to get an inspector on whatever widget is under your mouse pointer to make sure that the button you are looking at is in fact the one you think you are looking at. I used this to find a problem once where someone had subclassed some complicated window to add some functionality, and one of the buttons didn't work any more: turned out they were creating the same button again in the subclass constructor, which was overlaying the original's button (the one with all the event handlers).
I think some of this stuff might be more common in other languages now, but it wasn't in the mid-nineties. I know Java had a limited version of drop-to-frame a number of years ago, but it had some pretty cramping restrictions.
I don't think that's the case.
For one, the design and semantics of the language and overall environment force you to understand this and leverage those kind of features.
Second, Smalltalk being a niche language, it attracts programmers for its particularities and overall merits, and those are more likely to know and leverage those things than not. It's not like random corporate programmers are told to use Smalltalk and they use it like a C or Java. It's programmers who have sought after Smalltalk against the current trends that are using it today, and those know very well what it is.
I had to learn the interactivity stuff from people at the other company, which was staffed by people who'd been Smalltalk programmers for quite a while, and also people who had experience with other dynamic languages, particularly Common Lisp. That was where I really learned how to do the interactive stuff I mentioned above.
You might consider Smalltalk niche now, but in the short period of time before Java came around, it looked like Smalltalk was the future of enterprise computing. That is the period I am specifically talking about.
Imagine that your hot code replacement is also possible at any level of the JVM or CLR.
Would you expand on this? From a theoretical standpoint I can see how reloading only a single method could be more performant (and therefore more productive) than reloading an entire class or module. From a practical standpoint, if reloading a method ends up reloading a class or module to effect the reload, is there a noticeable difference or improvement? Or am I just misunderstanding?
(I happened to have spent part of day looking at cloxp and lively. Nice to come across you here as well. Nice work!)
I think that what the OP must have meant about this was that you can update a method without interfering with the program's current state, so while at a breakpoint say, you can fix a minor bug or perhaps add some debugging code or whatever, then resume, and all subsequent invocations of that method will use the new definition.