For my parents' first car - they were between a Lada Samara and a (then recently re-designed by Bertone) Skoda Favorit. I was more of a Lada person, but one of their friends convinced them that Skoda is much better and they went along with it. I was upset for quite a while - but now looking back at it - although Lada had its appeal, I see that they made the right choice with their limited amount of money.
They are not actually bypassing firewalls - therefore I think they are on ethically good grounds. Those sites show their full text for web crawlers - only not to humans. Basically, archive.is and the folk simulate that through various means. Headless browsers, better agent injection etc.
I always assumed so - because Google can index them full text. It used to be the case that you could see those full snapshots in Google as cache - this was before the sites strong armed Google to remove those snapshots from being accessible, then archive.* folk rose to power. You can test this yourself for searching for a unique quote on those sites and still getting hits in Google. But you are right - why could this not be achieved with a plugin then - don't know.
What this blog omits to mention and I think the most impressive part of Smalltalk ecosystem is the structure of the image - the application's state that you can freeze and distribute and resume elsewhere (makes supporting client side applications so much easier). The Smalltalk image is a very interesting beast. Look at it as a kind of immortality. Many current Smalltalk systems, Pharo, Squeak, VisualWorks among them, share a common ancestor, that is, a Smalltalk image from Xerox PARC. This common ancestor however is not some remote thing, but actually still alive in those modern systems. The modern variants were produced by sending messages to the objects in that image. Some of those messages actually morphed the current objects. Classes are full-blown objects, and creating new classes is done by sending messages to class objects. Some of the objects in a Smalltalk image may date back to 1972, when the first Smalltalk image bootstrapped! Smalltalk images never die, they just fade into something potentially fundamentally different. You should view your application building as not fundamentally different from creating a new Smalltalk version.
The image concept, in my opinion, is what really limited Smalltalk's appeal and distribution.
The image meant you basically got whatever state the developer ended up with, frozen in time, with no indication really of how they got there.
Think of today's modern systems and open source, with so many libraries easily downloadable and able to be incorporated in your system in a very reproducible way. Smalltalk folks derided this as a low tech, lowest-common-denominator approach. But in fact it gave us reusable components from disparate vendors and sources.
The image concept was a huge strength of Smalltalk but, really in the end in my opinion, one of the major areas that held it back.
Java in particular surged right past Smalltalk despite many shortcomings compared to it, partially because of this. The other part of course was being free at many levels. The other half of Smalltalk issues beyond the image one, was the cost of both developer licenses ($$$$!) and runtime licenses (ugh!).
> The image meant you basically got whatever state the developer ended up with, frozen in time, with no indication really of how they got there.
That wasn't a function of the image system. That was a product of your version control/CI/CD systems and your familiarity with them.
Consider that Docker and other container based systems also deploy images. No reason Smalltalk has to be any different.
I did software development work in Smalltalk in the 90's. We used version control (at one point, we used PVCS, which was horrible, but Envy was pretty sweet), had a build process and build servers that would build deploy images from vanilla images. Even without all that, the Smalltalk system kept a full change log of ever single operation it performed in order. In theory, someone could wipe their changelog, but that's the moral equivalent of deleting the source code for your binary. Image-based systems are no reason to abandon good engineering practices.
> Consider that Docker and other container based systems also deploy images.
Consider also that Docker was the only one to really get popular, perhaps because it promoted the idea of using a text-based "Dockerfile" as your source of truth and treating the images as transitory built artifacts (however false this was in practice).
It's still mostly true in practice. You don't add one more layer to your image to build the next version, you rebuild it from the Dockerfile, which is the opposite of Smalltalk approach.
It's a practical workflow that was actually adopted.
Next you'll be wondering whether changes were integrated continuously throughout the day — "This fine granularity of components enables highly concurrent development because changes can be tracked down to the individual method level …"
I remember early days of docker and how it was not really Dockerfiles early on, but people running image, editing in it, then committing this as new image.
Arguably it goes back to chroot-stuff, and LXC predates Docker by some five years or so. I don't remember the details well but Solaris had similar containers, maybe even before LXC arrived.
I'd say the clown popularised it outside of Linux and Unix sysadmin circles, rather than the Dockerfile format itself.
> Arguably it goes back to chroot-stuff, and LXC predates Docker by some five years or so. I don't remember the details well but Solaris had similar containers, maybe even before LXC arrived.
Solaris and FreeBSD had significantly better implementations of the containerisation/isolation piece from a technical standpoint. But they never caught on. I really think the Dockerfile made the difference.
> Solaris and FreeBSD had significantly better implementations of the containerisation/isolation piece from a technical standpoint.
FreeBSD jails (first) and Solaris zones (later) were 'heavier weight' than containers: folks perhaps did not want to manage a "light VM" to deploy applications.
I agree that the image concept was a problem, but I think that you're focused on the wrong detail.
The problem with an image based ecosystem that I see is that you are inevitably pushed towards using tools that live within that image. Now granted, those tools are able to be very powerful because they leverage and interact with the image itself. But the community contributing to that ecosystem is far smaller than the communities contributing to filesystem based tools.
The result is that people who are considering coming into the system, have to start with abandoning their familiar toolchain. And for all of the technical advantages of the new toolchain, the much smaller contributor base creates a worse is better situation. While the file-based system has fundamental technical limitations, the size of the ecosystem results in faster overall development, and eventually a superior system.
> But the community contributing to that ecosystem is far smaller than the communities contributing to filesystem based tools.
Another point is that you need to export your tools out of your own image so others can import it into their images. This impedance mismatch between image and filesystem was annoying.
I think we could quibble over the relative importance of these points, but I agree in general. The image locking you into that ecosystem is definitely a good point.
> The image meant you basically got whatever state the developer ended up with, frozen in time, with no indication really of how they got there.
I worked with a similar language, Actor (Smalltalk with an Algol-like syntax), and the usual way to deal with distribution was to “pack” (IIRC) the image by pointing to the class that your app is an instance of, and the tool would remove every other object that is not a requirement of your app. With that you got an image that started directly into your app, without any trace of the development environment.
One of the reasons Java got adopted, was that Smalltalk big names like IBM decided to go all in with Java.
It is no accident that Eclipse to this day still has a code navigation perspective based on Smalltalk, it has an incremental compiler similar to Smalltalk experience, and the virtual filesystem used by Eclipse workspaces mimic the behaviour of Smalltalk images.
the entire philosophy of Smalltalk was to think of software artifacts as living entities. You can just find yourself in a piece of software, fully inspect everything and engage with it by way of a software archaeology. To do away with the distinction between interacting, running and writing software.
They wanted to get away from syntax and files, like an inert recipe you have to rerun every time so I think if you do away with the image you do away with the core aspect of it.
Computing just in general didn't go the direction they wanted it to go in many ways I think it was too ambitious of an idea for the time. Personally I've always hoped it comes back.
The thing is that the "scripting" approach, is just so much easier to distribute. Just look at how popular python got. Smalltalk didn't understand that. The syntax is worse than python IMO (and also ruby of course).
A lot of great ideas are tried and tried and tried and eventually succeed, and what causes them to succeed is that someone finally creates an implementation that addresses the pragmatic and usability issues. Someone finally gets the details right.
Rust is a good example. We've had "safe" systems languages for a long time, but Rust was one of the first to address developer ergonomics well enough to catch on.
Another great example is HTTP and HTML. Hypertext systems existed before it, but none of them were flexible, deployable, open, interoperable, and simple enough to catch on.
IMHO we've never had a pure functional language that has taken off not because it's a terrible idea but because nobody's executed it well enough re: ergonomics and pragmatic concerns.
Typed out a response indicating the really good dev experience that F# and Elixir offer, but neither are "pure". Is Haskell the closest mainstream language to meet a purity requirement?
For this very reason I'm working on a development platform that makes all changes part of a cheaply stored crdt log. The log is part of the application, there are some types of simulations inside of this that we can only timestamp and replay but we can always derive the starting position with 100% accuracy.
>> most impressive part of Smalltalk ecosystem is the structure of the image
> The image concept, in my opinion, is what really limited Smalltalk's appeal and distribution.
I'd say these statements are both true. The image concept is very impressive and can be very useful, it certainly achieved a lot of bang for very little buck.
And it also was/is one of the major impediments for Smalltalk, at least after the mid 1980s.
The impressive bit is shown by pretty much the entire industry slowly and painfully recreating the Smalltalk image, just usually worse.
For example on macOS a lot of applications nowadays auto-save their state and will completely return to the state they were last in. So much that nowadays if you have a lot of TextEdit windows open and wish to make sure everything is safe, you kill the program, you don't quit it.
Also, all/most of the shared libraries and frameworks that come with the system are not loaded individually, instead they are combined into one huge image file that is mapped into your process. At some point they stopped shipping the individual framework and shared library binaries.
User interfaces have also trended in the direction of a an application that contains its own little world, rather than editing files that exist within the wider Unix filesystem.
The image accomplished all that and more and did so very efficiently. Both in execution speed and in amount of mechanism required: have a contiguous piece of memory. Write to disk, make a note of the start pointer. On load, map or read it into memory, fix up the pointers if you didn't manage to load at the same address and you're ready to go. On G4/G5 era Macs, the latter would take maybe a second or two, whereas Pages, for example, took forever to load if things weren't already cached, despite having much less total data to load.
But the drawbacks are also huge. You're really in your little world and going outside of it is painful. On an Alto in the mid to late 1970s I imagine that wasn't much of an issue, because there wasn't really much outside world to connect to, computer-wise, and where would you fit it on a 128KB machine (including the bitmap display)? But nowadays the disadvantages far outweigh the advantages.
With Objective-S, I am building on top of Cocoa's Bundle concept, so special directories that can contain executable code, data or both. Being directories, bundles can nest. You can treat a bundle as data that your program (possibly the IDE) can edit. But you can also plonk the same bundle in the Resources folder of an application to have it become part of that application. In fact, the IDE contains an operation to just turn the current bundle into an application, by copying a generic wrapper application form its own resources and then placing the current bundle into that freshly created/copide app.
Being directories, data resources in bundles can remain standard files, etc.
With Objective-S being either interpreted or compiled, a bundle with executable code can just contain the source code, which the interpreter will load and execute. Compiling the code inside a bundle to binaries is just an optimization step, the artifact is still a bundle. Removing source code of a bundle that has an executable binary is just an obfuscation/minimization step, the bundle is still the bundle.
The key is the plural in "Docker containers". You're not doing everything by modifying one Docker container that's been handed down over literally generations, you're rebuilding images as you need to, usually starting from a golden master, but sometimes starting from a scratch image into which you just copy individual files. It's the "cattle, not pets" mentality, whereas a Smalltalk or Lisp Machine image is the ultimate pet.
> You're not doing everything by modifying one Docker container that's been handed down over literally generations
You don't do that with Smalltalk, either, at least not for the last 30 years or so. Smalltalk has worked with version control systems for decades to maintain the code outside the image and collaborate with others without needing to share images.
I try not to think about these things, I've mostly worked with hardware-centric companies and on "legacy" systems. So many things they're doing that no one else does because 5-25 years ago everyone else figured out the lessons from 30-60 years ago, except for these companies.
> you're rebuilding images as you need to, usually starting from a golden master
For example, cp the "golden master" into the current directory and rename it "nbody.pharo_run.image".
"fileIn" the source code file (name passed on the commandline) "nbody.pharo" (and then cleanUp and garbageCollect) and "snapshot" the image.
Then invoke the program "main.st". In this example, the source code file defined a class method BenchmarksGame>>do: which performs a calculation and prints the result on stdout.
Except that's not really what happened. You're ignoring the range of in-image tools which kept track if who did what, where. From versioning of individual methods, to full blown distributed version control systems, which predated git.
Not to sound harsh or gatekeep, but folks who keep repeating the canard that "The Smalltalk image resulted from the developer just banging on the system", mostly never used smalltalk in the first place.
Give the original smalltalk devs some credit for knowing how to track code development over time.
No, I haven't ignored those tools. They were all stop-gaps that worked in a "meh" way to various degrees. Smalltalk was always optimized to one guy banging away on their solution. Add a second developer and things got much hairier, and more so as you kept adding them.
Hmm, well I don't know exactly when Monticello was first developed, but it was certainly in heavy use by the early 2000s. How is that "meh" when compared to ... cvs & subversion?
I don't know much about the systems used in commercial smalltalks of the 90s, but I'm sure they weren't "meh" either (others more knowledgeable than me about them can chime in).
image-centric development is seductive (I'm guilty). But the main issue isn't "we don't know what code got put where, and by whom". There were sophisticated tools available almost from the get go for that.
Its more a problem of dependencies not being pruned, because someone, somewhere wants to use it. So lots of stuff remained in the "blessed" image (I'm only referring to squeak here) which really ought not to have been in the standard distribution. And because it was there, some other unrelated project further down the line used a class here, a class there.
So when you later realise it needed to be pruned, it wasn't that easy.
But nevertheless, it was still done. Witness cuis.
In other words, it was a cultural problem, not a tooling problem. It's not that squeak had too few ways of persisting & distributing code - it had too many.
IMHO, the main problem was never the image, or lack of tools. It was lack of modularisation. All classes existed in the same global namespace. A clean implementation of modules early on would have been nice.
Interesting. Shows how aware they were of these 2025 criticisms, way back in the 80s (which shows how much of an oversimplification these criticisms are of the real situation).
You probably already know about this, but in case you didn't, there is 1 project which adds modules to cuis Smalltalk:
Digitalk’s Team/V unobtrusively introduced a non-reflective syntax and versioned source code using RCS. Team/V could forward and backwards migrate versions of Smalltalk “modules” within an running virtual image.
"When you use a browser to access a method, the system has to retrieve the source code for that method. Initially all the source code is found in the file we refer to as the sources file. … As you are evaluating expressions or making changes to class descriptions, your actions are logged onto an external file that we refer to as the changes file. If you change a method, the new source code is stored on the changes file, not back into the sources file. Thus the sources file is treated as shared and immutable; a private changes file must exist for each user."
1984 "Smalltalk-80 The Interactive Programming Environment" page 458
But the image isn’t just the code, or classes, it’s also the network of objects (instances). And that’s more difficult to version, or to merge branches of.
Given that the instantiation of those objects has been triggered by Smalltalk commands; those Smalltalk commands can be recorded and versioned and replayed to instantiate those objects.
It means that versioning operations, even just displaying the history, effectively have to run the full image from the beginning of the history, or take intermediate snapshots of the image. In addition, there is interaction between the source code changes and the recorded command history. It also doesn't address how merging would be practical. You would have to compare the state of two images side-by-side, or rather three, for three-way merges.
"Within each project, a set of changes you make to class descriptions is maintained. … Using a browser view of this set of changes, you can find out what you have been doing. Also, you can use the set of changes to create an external file containing descriptions of the modifications you have made to the system so that you can share your work with other users."
1984 "Smalltalk-80 The Interactive Programming Environment" page 46
~
The image is throw-away. It's a cache, not an archive.
"At the outset of a project involving two or more programmers: Do assign a member of the team to be the version manager. … The responsibilities of the version manager consist of collecting and cataloging code files submitted by all members of the team, periodically building a new system image incorporating all submitted code files, and releasing the image for use by the team. The version manager stores the current release and all code files for that release in a central place, allowing team members read access, and disallowing write access for anyone except the version manager."
1984 "Smalltalk-80 The Interactive Programming Environment" page 500
Adding to what you said. Squeak was a clean open source reimplementation (by the devs who did the original Smalltalk-80), so it's real history starts from there (ie: the 90s, not the 70s)
One thing to keep in mind is that smalltalks all have the same ability to save & load code to & from disk, just as any other programming environment. But, they also have the option of just using the image to persist, and iterate on that.
Squeak overdid that aspect of it, such that over time, it became hard to prune older side projects & and it just became increasingly bloated. Both Pharo & Cuis forked from squeak at about the same time.
Pharo images are fully bootstrapped from a seed.
Cuis is not quite there yet, but cuis from its inception went on a ruthless simplification drive (the number of classes in the system was reduced by about 500% !), so that it's base is effectively a "seed", and the rest of a cuis image is built up by importing projects (from disk & git) on demand.
But yeah, curating a set of images over time is remarkably enticing & friction free. Even in cuis, I find I have to force myself to keep flushing changes to my own packages.
Its not that the tools to use files are limited. In cuis, they're not. You can work on multiple different things WITHIN THE SAME IMAGE (changes to some builtins, a couple of your own projects, etc), and the system will keep track of what belongs where. So a couple of mouse clucks will fileout the relevant code to the relevant changesets & packages.
And yet - just banging on the same image is just ... fun, easy, enticing.
Small correction: they actually cloned/converted the Apple Smalltalk image, so those bits remained. The VM was created from scratch by writing it in Slang, a Smalltalk dialect that was essentially equivalent to BCPL and could be translated to C.
The VM in Slang had been previously published as part of the "blue book" (now that is what I call open source!) some 14 years before, and as the paper you linked to mentioned, Mario Wolczko at the University of Manchester had typed it in so it was available in machine readable form.
They did drop the object memory part completely and designed a new one from scratch.
Previously people had manually translated the VM from Slang to Pascal or C (I did so myself in 1986) but for this project they wrote a tool for that (in Smalltalk, of course).
Here is another copy of the "Back to the Future" paper:
No, they used a tool (SystemTracer) running inside the original Smalltalk that enumerated all the objects in the running image and serialized them in a new image format into a new image file. Every time the image file format changed, it was transformed like this. Smalltalk is very close to a biological system.
- Design a new Object Memory and image file format.
- Alter the ST-80 System Tracer to write an image in the new format.
- Eliminate uses of Mac Toolbox calls to restore Smalltalk- portability.
- Write a new file system with a simple, portable interface."
Thanks for the info. Hmm, it's kind of cool to think there might be a few classes in today's fully-accelerated-vector-graphics-morphic cuis system that were first keyed into the system on an Alto in the 70s :-)
In the world of containers, I wonder if one could use this feature to interrupt the execution of some computation, save the state somewhere (disk or object storage) and once the workload has been rescheduled on some other node, basically you boot up from your image file, re-establish network connections (if necessary) and just resume computation as if nothing happened.
https://criu.org/ (Checkpoint/Restore In Userspace) is a long-running project (i remember the name over a decade ago) worth checking... Ooh, looks like they made progress in conveniently connecting it to containers.
> makes supporting client side applications so much easier
I was thinking that supporting a Smalltalk application must be a nightmare because it is so malleable. Users can inspect and modify the entire system, no?
I used to think so, then watched as javascript in the browser rose to be the premium application platform - where the user has access to a console/repl, developer tools etc...
I think many people would suggest that this was more of an accident due to the ubiquity of the browser, though.
The transition from "websites" to "web apps" was well underway by the time the dev tools became a built-in browser feature - Chrome was notable for being the first browser to release with the console, inspectors, etc out of the box, but that came later. The developer experience was quite a bit rougher in the early days, and then better but still not native in the days of plugins like Firebug.
The web becoming the premium app distribution platform was, firstly, because the web was the lowest-common-denominator distribution channel. Javascript was just the tool that was available where everyone wanted to run.
The difference is the changes the user can make don’t flow back to the original. If the user hits refresh they get your copy of the web app, not theirs.
Say you made the foreground text color the same as the background text color, so you could no longer see the source code. You can no longer do anything. You can no longer save those changes. And then what?
Better, say you did that in a script file which additionally saved the image, so that image was now unusable. And then what?
The parent comment was talking about a deployed application, and making sure users can't modify the source code.
In that case, your image hopefully was built using source code from a VCS and no such changes will have been applied. This is not so different from building an app by pulling the latest version of the code from Git.
And if you did manage to commit changes that completely mess up your environment, you throw that image away, take a vanilla one and load your source code into it. Again, not so different from using Git.
> Users can inspect and modify the entire system, no?
That should make the Smalltalk family popular with free software proponents. That makes me curious why that is not the case in history. The efforts of FSF on Smalltalk pale in comparison with those on C, Lisp and other languages.
C was only open until AT&T was allowed to charge for UNIX, and it became an international standard in 1989.
It was thanks to GCC that most folks actually got a free C compiler after those events, coupled with Sun starting the trend among UNIX vendors that developer tools would be extra license, no longer available on a regular UNIX installation.
That part is also cool. I'd like this in ruby too, e. g. where we could have tons of objects reflect on that state, and just resume work there. Everything is an object. Squeak everywhere, but to also retain the "scripting" (light) commandline approach. Nobody in smalltalk really understood why "scripting" is important. Python showed why.
reply