Smalltalk is small. All you can do is
Send a message -- invoke the method found by looking up the message selector in the class of the receiver
Read the value of a variable. Variables hold references to objects.
Read the value of a literal, i.e. 'hello' or 3.
Assign a variable -- store a reference to an object in a variable (could be a temporary (method scoped) variable or an instance variable)
Return a value -- push an object on the stack to be found by the invoker of this method
Create a block -- an object that refers to some code you can evaluate. It is a closure, like in Scheme, and is used to make control structures. It is the only thing on this list that is complicated.
That's it. Everything else is just window dressing. Integers in a limited range generally have a special implementation, as do Characters and Booleans, but these are optimizations and don't generally intrude on the programmer's consciousness. For all practical purposes, Integers and Booleans are objects just like any other kind of object.
Some methods are defined as primitives. When you go to look at the method definition, you don't see any interesting code, just something of the form . There are primitives for arithmetic, accessing arrays and strings, starting a process, doing I/O, etc. There are usually a few hundred of them. Of these, most are optimization. You could get by with very few primitives (how many? 10? 20?). For example it is possible to write a smalltalk interpreter in Java as host language with 32 primitives (more at www.antlr.org ).
In theory, primitives aren't needed at all. One could implement integers as described in Lambda Calculus, i.e. 0 is represented by the block [:f :x | x], 1 is presented by [:f :x | f value: x], 2 by [:f :x | (f value: x) value: x], etc. Of course, this would lead to impractical slowness. Nevertheless, one day we might decide to do it that way.
Most of the language implementation is represented by objects. Classes are objects, methods are objects, even stack contexts are objects. The debugger is just an editor of stack contexts. In general, these classes, like Array and String, are only special in the sense that the virtual machine knows their implementation (so be careful about changing them!) and some of their methods are implemented by primitives. Small Integer and Character are even more special because you can't subclass them. If you want to make a new kind of integer then you need to subclass Integer, not Small Integer.
Instance variables, temporary variables and parameters are NOT objects. Instead, they refer to objects. Interestingly, global variables and class variables are objects in their own right, instances of class Association. This is not part of the language definition, but all the versions of Smalltalk that I have used do it this way.
So, "everything in Smalltalk is an object, and all computation is messages between objects" is pretty close to the truth. Variables are not objects and reading and writing a variable is not a message send. The languages Self Language and Io Language show that you can eliminate variables from the language and replace everything by messages. This makes the language even simpler, but it is already pretty simple.
''This description is useful... Does anybody know where I can find a concise account of this in the literature?
You just read it. I don't think anything like this has been published in such condensed form. Is Wiki citeable (given that it may change before you get there?)
See How To Cite Wiki
Can anyone recommend books or articles on the core principles of Smalltalk? - i.e. what are the basic constructs necessary for the Smalltalk computational model to work?
Apparently, "everything isn't an object" afterall - some things are primitives. So it appears that Smalltalk has a basic set of core concepts for computing... where can I discover a concise description of these concepts. For example:
What is a primitive?
A method whose implementation is in the virtual machine, rather than in Smalltalk. Examples are + for Small Integers, the quit primitive, the method to open a file at the OS level, etc...
How do they differ from conventional classes?
Primitives are methods, not classes. There are no primitive types as in Java.
Is there a minimum set of classes/primitives which are essential for computation?
You might want to look at Learning Works. It's a simplified version of Smalltalk used for teaching. It hides lots of the advanced stuff until you understand the basics of what's going on in the environment.
I'm not after how to implement a virtual machine - just the principles of the absolute core of the language...
I would like to note that even primitive methods are represented in the system as a MethodObject. However, message passing bottoms out at a primitive method and some real work is performed.
Noticing something kind of funky. When you write something like [:i|(Transcript: show 'Hello World') cr]. Colon is used after the message name Transcript, but before the block variable i. Is the idea that there is some invisible message name on the left of :i ? That is, that "a : b" is a form of the language and the "a" is optional?
Actually you write [ :i | Transcript show: 'Hello World'; cr]. A keyword message selector ends in colon and separates its words with colon, as in #detect:ifNone:. The ":" in front of an argument in a block is syntactic. Free-standing ":" doesn't mean anything. You could in principle define the symbol #: and use it as an operator. There may be some subtle reason why it wouldn't work, but if there is I'm not aware of it.
Smalltalk has way too many colons. They are in there to simplify the parser. We forgive the language designers because they did so much else right.
Smalltalk does not have way too many colons, you just haven't drank the kool aid deeply enough! Oh, and C'ish languages have way too many periods. ;)
Does Smalltalk Syntax really have too many of anything? You can fit Smalltalk Syntax Ina Postcard. Can you do that with many languages? fs.
See original on c2.com