This is the 2nd part to my previous post, Squeak is like an operating system.
It’s easy to get lulled into the notion when programming in Smalltalk that you can use it like you would a programming language that is separated from the OS, that uses libraries, and is only linked in by a loader. Indeed Smalltalk is a programming language, but more in the sense that Bourne Shell is a programming language on Unix, and you’re using it logged in as “root”. That’s a bit of a bad analogy, because I don’t mean to imply that Smalltalk is a scripting language that uses terse symbols, but the power that you have over the system is the same (in this case, the Squeak image).
In Unix, you manipulate processes and files. In Squeak, you manipulate objects. Everything is an object.
I had an interesting “beginner root” experience with Squeak recently, and it highlights a difference between Ruby (file-based) and Smalltalk (image-based). Some might judge it in Ruby’s favor. I was doing some experimenting in a Workspace. To further the analogy, think of a Workspace as a command line shell instance in X-Windows. I had been using a variable called “duration” in my code. It was late. I was tired (really interested in what I was doing), and I got to a point where I didn’t need this variable. Cognizant of the fact that in certain workspaces variables hang around, I decided I wanted to get rid of the object it was holding, but I was a bit spacey and couldn’t remember the exact spelling of it. I had already changed the code that used it. So I evaluated:
duration := nil
Duration := nil
just to be sure I got both spellings. At first nothing weird happened, but then I tried to save the image and quit.
I had forgotten that 1) all variables in Smalltalk begin in lower-case, and 2) “Duration” (with the capital D) is the name of a class. Smalltalk is case-sensitive. Instead of saving, I got an exception dialog saying “Message Not Understood”. I found the source of the error, and for some mysterious reason, a message being passed to the Duration class seemed to be causing the error. I inspected “Duration” in the code and Smalltalk said “Unknown object”. Alright. So it wasn’t the message. Still, I thought, “Huh. Wonder what that’s about?” I ended up just quitting without saving. I realized the next day the reason I got the error is I had deleted the Duration class from the image (in memory, not on disk)! I confirmed this by trying it again, bringing up a code browser and trying to search for the Duration class. Nothing. I thought, “Wow. That’s pretty dangerous,” just being able to make a spelling error and delete a critical class without warning.
Say you’re using Unix, and you’re at the command line, and there’s a critical executable that Unix uses to calculate the passage of time, called Duration (I know this would normally involve using a time structure in C and some API calls, but bear with me). What I did would be the equivalent to saying, “mv Duration /dev/null”, and when the system tried to shut down, it couldn’t find it, and aborted the shutdown. I know this sounds weird, because I just said the image on disk was unaltered. Anything that is actively available as an object in Squeak is in memory, not on disk. The disk image is roughly equivalent to the file that’s created when you put your computer into hibernation. It’s just a byte for byte copy of what was in memory.
Unix treats directories/files, processes, and shell variables differently. It treats them each as separate “species”. One does not work like the other, and has no relationship with the other. I know it’s often said of Unix that “everything is a file”, but there are these distinctions.
Another fundamental difference between Unix and Squeak is Unix is process-oriented. In Unix, to start up a new process entity, you run an executable with command line arguments. This can be done via. GUI menus, but still this is what’s going on. In Squeak you run something by passing a message to a class that instantiates one or more new objects. This is typically done via. icons and menus, but at heart this is what’s going on.
Anyway, back to my dilemma. I was looking to see if there was a way to easily fix this situation, since I considered this behavior to be a bug. I didn’t like that it did this without warning. It turned out to be more complicated than I thought. I realized that it would take a heuristic analyzer to determine that what I was doing was dangerous.
I did a little research, using Google to search the Squeak developers list, looking up the keywords “Squeak ‘idiot proof'”, and interestingly, the first entry that came up was from 1998 where Paul Fernhout had done something very similar. He asked, “Shouldn’t we prevent this?” Here’s what he did:
Dictionary become: nil
Dictionary is, again, a class. become: is a message handled by ProtoObject, the root class of every class in the system. In this case it makes every variable in the entire system that used to point to Dictionary point to nil. The method description also says, “and vice versa”, which I take to mean that every variable in the system that pointed to the argument in become: would point to Dictionary (to use the example). I’m guessing that nil is a special case, but I don’t know.
Anyway, this caused Squeak to crash. The consensus that ensued was that this was okay. Squeak was designed to be a fully modifiable system. In fact, Alan Kay has often said that he wishes that people would take Squeak and use it to create a better system than itself. “Obsolete the darn thing,” he says. The argument on the developers list was if it was made crash-proof, anticipating every possible way it could crash, it would become less of what it was intended to be. Someone feared that, “if you make it idiot proof, then only idiots will use it.” The conclusion seemed to be that Squeak programmers should just follow “the doctor’s rule”: The patient says, “It hurts when I do this.” The doctor says, “Well, don’t do that.”
I can see that this argument has validity, but in this particular instance, I don’t like this explanation. It seems to me that this is an area where some error checking could be easily implemented. Isn’t it erroneous to put nil in for become:? Maybe the answer is no. I at least have an excuse, since I was using the := operator, which is a primitive, and it’s much harder to check for this sort of thing in that context.
I also realized that the reason that code browsers can warn you about doing such things easily is they have menu options for doing things like deleting a class, and they throw up a warning if you try to do that. The browser can clearly make out what you’re trying to do, and check if there are dependencies on what you’re deleting. Checking for “Duration := nil” would be akin to a virus scanner looking for suspicious behavior. I don’t believe even a browser would pick up on this piece of code.
This example drove home the point for me that Squeak is like an operating system, and I as a developer am logged in as root–I can do anything, which means I can royally screw the system up (the image) if I don’t know what I’m doing.
I do have a way out of a mess, though, with Squeak. Fortunately, since it’s image-based, if I had managed to save a screwed-up image, I could just substitute a working image. It’s a good idea to keep a backup “clean” image around for such occasions, that you can just make a copy of. I wouldn’t need to reinstall the OS (to use the analogy). It’s like what people who use virtualization software do to manage different operating systems. They save disk images of their sessions. If one becomes screwed up or infected with a virus, they can just substitute a good one and delete the bad one. Problem solved.
For the most part, I wouldn’t lose any source code either, because that’s all saved in changesets, which I could recover (though Workspaces are only saved if you explicitly save them).
Another thing I could’ve done is opened up another instance of Squeak on a good image, filed out the Duration class (have Squeak serialize the class definition to a text file), and then filed it in (deserialized it), in the corrupted image. I imagine that would’ve solved the problem in my case.
Having said all this, I don’t mean to say that if you’re a Squeak user, working at a more abstract level, say with eToys, that you’re likely to experience a crash in the system. That level of use is pretty stable. Individual apps. may crash, and people have complained about apps. getting messed up in the newer versions, but the system will stay up.
I can understand why some like Ruby. You get access to Smalltalk-like language features, without having “root” access, and thereby the ability to mess things up in the runtime environment. The core runtime is written in C, which conveys a “None but the brave enter here” message. It’s compatible with the file-based paradigm that most developers are familiar with. From what I hear, with the way programming teams are staffed these days at large firms, a technology like Squeak in unskilled hands would probably lead to problems. It’s like the saying in Spiderman: “With power comes responsibility.” Squeak gives the programmer a lot of power, and some power to mess things up. Interestingly, in the 1998 discussion I link to, there was a distinction made between “shooting yourself in the foot” in Smalltalk vs. doing the same in a language like C. The commenter said that a C programmer has to be much more careful than a Squeak programmer does, because a) pointers in C are dangerous, and b) you can’t avoid using them. Whereas in Squeak you don’t have to use facilities that are dangerous to get something useful done. In fact, if you do screw up, Squeak offers several ways you can recover.
In closing, I’ll say that just as a seasoned Unix administrator would never say “rm -r *” from the root directory (though Unix would allow such a command to be executed, destructive as it is), people learning Squeak come to the realization that they have the full power of the system in their hands, and it behooves them to use it with discipline. I know that in a Unix shell you can set up an alias for rm that says “rm -i” that forces a warning. I suppose such an option could be built into Squeak if there was the desire for that. It would depend a lot on context, and Squeak doesn’t really embody that concept at this point.