Around 1990, I was a graduate student in Prof. Red Whittaker's field robotics group at Carnegie Mellon. In Porter Hall, I was fortunate to have a Sun 3/60 workstation on my desk. It had a Smalltalk-80. I learned to program it using Goldberg & Robson and other books from ParcPlace Systems.
The programming environment was fantastic, better than anything I have seen before or since. You always ran it full screen, and it loaded up the Smalltalk image from disk. As the article says, you were in the actual live image. Editing, running, inspecting the run-time objects, or debugging: all these tasks were done in the exact same environment. When you came into the office in the morning, the entire environment booted up immediately to where you had left it the previous day.
The image had objects representing everything, including your screen, keyboard, and mouse. Your code could respond to inputs and control every pixel on the screen. I did all my Computer Graphics assignments in Smalltalk. And of course, I wrote fast video games.
I used the system to develop programs for my Ph.D thesis, which involved geometric task planning for robots. One of the programs ran and displayed a simulation of a robot moving in a workspace with obstacles and other things. I had to capture many successive screenshots for my papers and my thesis.
Everybody at CMU then wrote their papers and theses in Scribe, the document generation system written by Brian Reid decades earlier. Scribe was a program that took your markup in a plain text file (sort of at a LaTeX level: @document, @section, etc.) and generated Postscript for the printer.
I never had enough disk space to store so many full screen-size raster images. So, of course, instead of taking screenshots, I modified my program to emit Postscript code, and inserted it into my thesis. I had to hack the pictures into the Postscript generation process somehow. The resulting pictures were vector graphics using Postscript commands. They looked nice because they were much higher resolution than a screenshot could have been.
This is my favorite video by Newspeak's creator Gilad Bracha: https://youtu.be/BDwlEJGP3Mk?si=Z0ud1yRqIjVvT4oO
Were the users running, say, Windows and then the Smalltalk "OS" would be running on top of that, but in a sort of "kiosk mode" where its full OS-ness was suppressed and it was dedicated to showing a single interface?
But destiny made CPUs win and now we're using AI to chew their accidental complexity for us.
The thing (for me) about Smalltalk was the thought to code ratio. It was awesome. It had a pretty good balance of less is more. Where working in Swift and Kotlin feel like trying to navigate the many nuances of American football or cricket, Smalltalk was like playing soccer/football-sans-america. The syntax is simple. And the computation model is straitforward and simple.
Elixir is kind of like that, computationally, a few simple concepts and everything builds on that. The saddest part about Elixir is that it ran with the whole do/end syntax. Drives me nuts. But I love that computationally, though different than Smalltalk, it’s like Smalltalk in that it’s a simple consistent model.
I've experienced this a few different times: with Microsoft BASIC-80 (and GW-BASIC), with SBCL and SLIME, with LOGO, with GForth, with OpenFirmware, with MS-DOS DEBUG.COM, with Jupyter, and of course with Squeak. It really is nice.
It used to be the normal way of using computers; before memory protection, it was sort of the only way of using computers. There wasn't another memory space for the monitor to run in, and the monitor was what you used to do things like load programs and debug them. This approach continued as the default into many early timesharing systems like RT-11 and TENEX: there might be one virtual machine (memory space) per user, but the virtual machine you typed system commands into was the same one that ran your application. TENEX offered the alternative of running DDT (the debugger) in a different memory space so bugs in the application couldn't corrupt it, and that was the approach taken in ITS as well, where DDT was your normal shell user interface instead of an enhanced one.
All this seems very weird from the Unix/VMS/Win32 perspective where obviously the shell is a different process from your text editor, and it's designed for launching black-box programs rather than inspecting their internal memory state, but evolutionarily it was sort of the natural progression from a computer operator single-stepping a computer (with no memory protection) through their program with a toggle switch as they attempted to figure out why it wasn't working.
One of the nicest things about this way of working is halt-and-continue. Current versions of Microsoft Visual Studio offer sometimes halt and continue. In MBASIC you could always halt and continue. ^C halted the program, at which point you could examine variables, make arbitrary changes to the program, GOTO a line number, or just CONT to continue where you'd interrupted it. Smalltalk, SLIME, or ITS allows you to program in this way; if you like, you can refrain from defining each method (or function or subroutine) until the program tries to execute it, at which point it halts in the debugger, and you can write the code for the method and continue.
This is an extremely machine-efficient approach; you never waste cycles on restarting the program from the beginning unless you're going to debug program initialization. And in Smalltalk there isn't really a beginning at all, or rather, the beginning was something like 50 years ago.
Myself, though, I feel that the hard part of programming is debugging, which requires the experimental method. And the hard part of the experimental method is reproducibility. So I'm much more enthusiastic about making my program's execution reproducible so that I can debug faster, which conflicts with "you're in the running environment". (As Rappin says, "Code could depend on the state of the image in ways that were hard to replicate in deploys." I experience this today in Jupyter. It's annoying to spend a bunch of time trying to track down a bug that doesn't exist when you restart from scratch; worse is when the program works fine until you restart it from scratch.) So I'm much more excited about things like Hypothesis (https://news.ycombinator.com/item?id=45818562) than I am about edit-and-continue.
Paul Graham wrote somewhere (I can't find it now) about how in Viaweb's early days he would often fix a bug while still on the phone with the customer who was experiencing it, because he could just tweak the running CLisp process. But you can do the same thing in PHP or with CGI without sacrificing much reproducibility—your system's durable data lives in MariaDB or SQLite, which is much more inspectable and snapshottable than a soup of Smalltalk objects pointing to each other. (#CoddWasRight!) Especially since the broad adoption of the Rails model of building your database schema out of a sequence of "migrations".
Also much happier. C++ back then is not the C++ you use today.
Elixir kind of got close too (prettier "erlang") - to have fault-tolerant mini-CPUs ("objects", aka similar to biological cells). The problem is that even people with grand ideas, such as Alan Kay, are not automatically great language designers. Matz is a better language designer than Alan Kay, for instance, whereas Alan Kay has the better ideas. It's a trade-off.
Note: I myself would not know how a language should look like that would follow Alan Kay's vision closer. It is definitely not smalltalk; it is also not ruby, though ruby is very good. I know I would suck as language designer, but as an improvement I would have a language similar to ruby (no, not crystal - crystal is a worse "ruby"), with a stronger focus on speed (perhaps have a second language that can be as fast as C here and be similar) and with a much stronger focus on what erlang brought to the table; that would get us close to, say, around 85% or 90%. And then add the rest that could fulfil Alan Kay's vision. Of course we need a specification too, because just saying "90% of his vision" is also pointless. I would perhaps start from erlang, retain the good bits, make it a modern variant of OOP (and OOP is also defined differently in different programming languages, so we need to define that term too, in the specification).