I want to learn Smalltalk

dear forum,

I am not a programmer but I am very (and I mean, very) interested in programming. There are programmers who work real hard and for very understandable reasons are not very interested in history and fundamentals, but I am. I hope you guys will be friendly enough to give me directions, the reason I am doing this in a forum all about programming languages is that I know no one personally who can help me with this, and this thread can serve others.

I've heard (read) so much about Smalltalk (specifically, how cute it is as a language) but unfortunately the omniscient web didn't help me much (I know, weird). I have a fair bit of understanding of Java and (to a lesser extent) C++ (I am not comfortable with template wizadry, to be specific). The language I like most so far is Haskell, feel free to use any of these to make a point. What I am interested about the most is the difference between Java and Smalltalk.

I went to www.smalltalk.org, www.squeak.org, and some other websites. They had free books. But most of those books are in very weird formats (pictures embedded in PDF for example) and taught programming in Smalltalk itself, but I am not going to *use* Smalltalk anyway. I have a feeling that none of the articles/tutorials/books/documentations highlighted the *ideas* behind Smalltalk. They are mostly about how OO influences software construction. We know that pretty well by now. But I want to know why Smalltalk is the definitive OO language.

The questions I have are very naive (so if you don't feel like it, please just point me to relevant books or, better, webpages):
- classes are first-class objects? whatever does that mean? examples?
- the difference between 'self' and 'this' (in Java)?
- isn't Smalltalk dynamically typed? how do classes interact with dynamic typing?
- both functional languages and Smalltalk exhibit 'minimal' syntax in a sense, am I right? why? how? is there a very easy way to embed one into another? does currying have a Smalltalk counterpart?
- why do people call Smalltalk "pure OO"? apart from the superficial primitive types in Java, aren't everything else objects? what does it mean to be "pure OO"?
- interfaces? do they make sense?
- is there any intuitive reflection mechanism in Smalltalk?

So, in a sense, what I really need is a language report, not tutorials and introduction to OO principles. is there any? the functional counterpart of what I am looking for would be the Haskell98 report. with a bit of explanation on what is there and what is left out and why. please raise other questions as well.

cheers! may 2007 bring joy and happiness to your life. specially if 2006 didn't ;)

[PostScript: I noticed the frames and slots thread and I think the questions I want answers of could appear there as well, I'm keeping an eye on that one too!]

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Early History of Smalltalk

I recommend The Early History of Smalltalk for the overall background. Your more specific questions would best be answered by reading a book like Smalltalk 80: The Language.

Early history

Fascinating stories! I'm overwhelmed! But, learning the language first, then its history. "Smalltalk 80: The Language", does it have an online PDF version? Preferrably typeset in LaTeX?

Thanks again! All that happened even before I was born! My head is spinning...

Co-routines were popular even then? I hope by "co-routine" he means functions than remember what happened the last time they were called? as in C# (2.0):

IEnumerator<int> callMeAgain() {
  yield return 0;
  yield return 1;
  yield return 2;
}

erm... does he? How would I go about implementing message dispatch using co-routines?

Everything's an object

Personally, I think working with Smalltalk collections was the most liberating thing I got from the language, but YMMV. I put together some Smalltalk notes if you want the terse guide.

- classes are first-class objects? whatever does that mean? examples?

It means that whatever you can do with an object, you can do with a class (and vice versa). Knowing that classes are just objects, you have programmatic control over classes and how they create objects (no need for one set of logic that applies to static methods/properties, and another that applies to instance methods/properties).

the difference between 'self' and 'this' (in Java)?

They can be thought of as the same. However, in Java, you invoke a method for an object. In Smalltalk, it's more beneficial to think of it as sending a message to an object. So, in Java, this is just an indirect reference to get to the method you want to call. Whereas, in Smalltalk, this is an object, and I can send a message MyMessage: but I don't really call the method directly.

- isn't Smalltalk dynamically typed? how do classes interact with dynamic typing?

Classes are more of a convenience method for creating objects in Smalltalk. They are just one of many methods that could theoretically be used to create objects (the Self language is basically a class-less Smalltalk). As for dynamic typing, Smalltalk allows you to invoke a method that does not exist. A Smalltalk object can listen for all messages, including methods that it does not understand, and take appropriate action. A proxy stub can be created within a few lines of code, allowing for objects that can be distributed.

- both functional languages and Smalltalk exhibit 'minimal' syntax in a sense, am I right? why? how? is there a very easy way to embed one into another? does currying have a Smalltalk counterpart?

Minimal syntax can have the advantage of being extendible. Smalltalk doesn't have the idea of functions or currying, but it does have the idea that objects are first class. So you can have the idea of currying message sends to objects (a message sent to an object returns an object, and a message can be sent to that returned object).

- why do people call Smalltalk "pure OO"? apart from the superficial primitive types in Java, aren't everything else objects? what does it mean to be "pure OO"?

Those primitive types are not superficial - they are the basic building blocks. It'd be hard to write a program that does not use numbers. More generally I'd say that Smalltalk tries to capture the idea of objects as independent computing entities. Think of each object as a computer. You can send messages to these computers. And in turn, these computers can send messages to other computers and return a message in response. When you invoke a message, you are not jumping to code that is embedded in that computer. You are requesting that the computer do something for you. That computer is free to perform a requested chore in any manner that it so chooses. The idea here is that objects are computing entities. They can act in federation, but they should not be viewed as convenience mechanisms for grouping code. The encapsulation is at the object level, not at the level of classes defined within the source code.

(Now underneath the hood, things are not quite that simple. Smalltalk will try to optimize where it can, and make messages look like function calls. And Java does encapsulate object instances to where they may act like independent entities.)

interfaces? do they make sense?

Well, the problem with many static OOP languages is that they conflate the ideas of type and code inheritance. Java takes the stand that classes should have single inheritance, allowing code reuse along a single axis of inheritance. However, because an object can have multiple types that don't necessarily follow a code inheritance hierarchy, interfaces are introduced. From a practical standpoint, this means that Java has two schemes for establishing types. And determinng which is better to use in a particular situation is not always straightforward. Personally, I'd prefer languages that seperate the ideas of code inheritance from the interfaces to an object. Or put another way, I'd prefer that all typing be done through interfaces. Of course, Smalltalk solves this problem by not really having a type mechanism. Objects respond to messages. Informally, if an an object responds to a message, then it is can be considered as a member of that type (duck typing).

is there any intuitive reflection mechanism in Smalltalk?

Reflection in Smalltalk is intuitive to the extent that all you do is send messages to an object. The image (the place where objects live) in Smalltalk can also be quite powerful.

select: do: collect: ... fold: !!!!

Smalltalk allows you to invoke a method that does not exist.
It lets you /try/. Just as a web browser lets you try to read a webpage that does not exist. Just as Java lets you try to dereference nil.

Smalltalk doesn't have the idea of functions...
Maybe you should look at those collection hierarchy enumeration methods again ;-)

All messages

It lets you /try/. Just as a web browser lets you try to read a webpage that does not exist.

Webpages is not a bad example. By analogy, if the web were a statically typed language, your browser would prevent you from ever requesting a page that did not exist. When you started up your browser, the browser would locate a directory of all known web pages. If you tried to load a page that did not exist, the browser would not bother sending a message to a target server. Your browser does not recognize the page, so it doesn't allow you to test the waters. As the web actually exists, a request for a web page is just a request (a message) to a target server. The server has the option of showing you a page. That page may correspond to a file that happens to be the same name as the one you requested. Or it may decide you do not have authority to view that web page. Or it may decide that you are requesting gibberish (doesNotUnderstand:). In that case, the webserver can either send a 404 response back. Or it can redirect you to a more meaningful error message page. The server sees all messages, including the ones for pages that do not exist.

Just as Java lets you try to dereference nil.

Being as nil is not an object in Java (another primitive), a method does not get called. Instead an exception is generated, which can be caught.

Maybe you should look at those collection hierarchy enumeration methods again ;-)

I may be going out on a limb here, but I'd say that Smalltalk doesn't have functions. Yes, there are messages that can be used to get the same effects that you see with functions (and subsequently currying), but all these collection methods (select: do: collect: fold:) are nothing more than messages that are understood by the various collection objects. There are also code blocks, and they can be used in a similar manner to lambdas, but even the code blocks are at some level objects.

A fun and confusing thing

The server sees all messages, including the ones for pages that do not exist.
And that's valuable because we don't have a way to figure out which pages exist - if we could magically know before sending the request whether the request would result in a viewable page that would be just fine.

Being as nil is not an object in Java (another primitive), a method does not get called. Instead an exception is generated, which can be caught.
The default behaviour in Smalltalk also results in an exception which can be caught, the interesting thing is that in Smalltalk we can change that default behaviour, the behaviour is defined by objects and methods that we can modify - if the behaviour was defined by objects and methods that we could not modify then it wouldn't be very interesting.

I may be going out on a limb here, but I'd say that Smalltalk doesn't have functions. ...There are also code blocks, and they can be used in a similar manner to lambdas, but even the code blocks are at some level objects.
The fun and confusing thing about Smalltalk is that most of the mechanisms used in the language implementation, and the abstractions used in the libraries, and our programs are all at the same level - they are all just objects.

Most of the time, thinking that a Block is an object is thinking at the wrong level of abstraction - the fact that a Block is an object is an implementation detail. The interesting thing about a Block is that we can define anonymous computations, apply them to arguments and get results.

accumulated notes

Chris Rathman wrote:
I put together some Smalltalk notes if you want the terse guide.

Thanks. I found this bit confusing though:
Class Instance: unique to each instance of a class

Instance Variables: unique to each instance
What's the difference? Is this relevant?

(no need for one set of logic that applies to static
methods/properties, and another that applies to instance
methods/properties).

(a message sent to an object returns an object, and a message can be sent to that returned object).
I guess this is the bit that confuses me most. Consider,

y := x indexOf: $e ifAbsent: [0].

Could you please explain the actual meaning of it? Who is the receiver of the message? x, I suppose. Does x receive both messages at once? or does (x indexOf: $e) receive ifAbsent[0]? Binary messages were mentioned a couple of time but I guess a Java programmer's intuition would be that x is the object, indexOf is the method, $e is the method argument. Then s/he gets lost if s/he is familiar with Haskell. ;-) Specially when what follows is another method. What's the point of ; operators, by the way? I'm sorry to bug you like this but my wishful thinking is that being pretty confident about these issues will help me understand Oleg Kiselyov's OO paper on Haskell. I guess it's pretty inconsiderate of me not to do my own research :-) But I thought you guys will enjoy relishing the memories anyway 8-)

Those primitive types are not superficial erm... I didn't actually mean the primitive types are superficial. What I meant to say is that treating them as 'value' types (whereas objects are all 'reference's) in Java is a superficial difference I am willing to overlook. What I gathered so far is that, since Scala treats primitive types as objects as well (via autoboxing/unboxing?) the claim that it is "pure OO" is more-or-less justified because there's nothing more to it. Inappropriate statement? The "classes are first-class objects" issue, with the reflection API in Java, seems a bit overrated to me, if you don't mind me saying that. Does Smalltalk allow runtime method redefinition? That would definitely be something... in my humble opinion Smalltalk (with duck typing, as I understand it) is a (fantastic!) scripting language!

Isaac Gouy wrote:
Most of the time, thinking that a Block is an object is thinking at the wrong level of abstraction - the fact that a Block is an object is an implementation detail. The interesting thing about a Block is that we can define anonymous computations, apply them to arguments and get results.
Erm... sound like lambda calculus to me! What messages would a block of code (as an object) understand? Could you show me with nullary, unary, and binary functions (lambdas, code blocks with local variables, whatever... I have happy with a lack of knowledge of terminology).

Cheers, and thanks!

it's pretty inconsiderate

Who is the receiver of the message? x, I suppose.
I Can Read C++ and Java But I Can’t Read Smalltalk

Download VisualWorks NonCommercial and explore!

Thanks. I found this bit

Thanks. I found this bit confusing though:
Class Instance: unique to each instance of a class

Instance Variables: unique to each instance
What's the difference? Is this relevant?

From a Java perspective, they would label the first as static variables (one per class) and the second as instance variables (one per instance).

y := x indexOf: $e ifAbsent: [0].
Could you please explain the actual meaning of it? Who is the receiver of the message? x, I suppose. Does x receive both messages at once? or does (x indexOf: $e) receive ifAbsent[0]?

x receives the message, but the syntax of Smalltalk does not interpret this as two messages. Instead, there is a single message to the x object named "indexOf: ifAbsent:".

With two keywords, you'd have three possibilities:

   "x receives a single message #indexOf:ifAbsent:"
   y := x indexOf: $e ifAbsent: [0].

   "x receives two messages #indexOf: followed by #ifAbsent:"
   y := x indexOf: $e; ifAbsent: [0].

   "x receives a single message #indexOf:
    then the object returned by that call receives the message #ifAbsent:"  
   y := (x indexOf: $e) ifAbsent: [0].

What's the point of ; operators, by the way?

This is a form of syntactic sugar to allow sending multiple messages to the same object. As I said, multiple keywords after an object form a single message, so the semicolon acts as a separator for where one message ends and another starts.
The "classes are first-class objects" issue, with the reflection API in Java, seems a bit overrated to me, if you don't mind me saying that.
What constitutes a useful technique from one programmer's standpoint, may be useless from another's - dependent on both the style proclivities of the person and upon the domain and environment that the person works in. Personally, I am trying to take some code that works on a desktop with a single user and reuse it in another application that runs over the internet with multiple users. Some of the code happens to be using static methods to keep track of context. Unfortunately, static methods do not follow an inheritance hierarchy. In Smalltalk, I could use the same object-oriented techiques for class level methods as I do for instance level methods. From a Java perspective, it's almost like there are two languages - one for static and one for instance. Of course, whether that particular piece is meaningful for a particular situation is subject mostly to whether it interferes with what you are trying to accomplish.

The "classes are first-class objects" issue, with the reflection API in Java, seems a bit overrated to me, if you don't mind me saying that.

I find the reflection to be more seamless, but of course that's just an opinion. But then I also think that many of the uses of reflection in Java are simply techniques to get dynamic dispatch. Since Smalltalk does require you to look up a method before calling it, you don't need to use reflection in Smalltalk to get this effect. I also mentioned the Smalltalk Image, which is both a source or power and weakness. When it comes to reflection, the image allows some interesting possibilities (though it should be mentioned that some of the Java development environments borrowed ideas from Smalltalk and try to emulate the image for development purposes).
Does Smalltalk allow runtime method redefinition? That would definitely be something... in my humble opinion Smalltalk (with duck typing, as I understand it) is a (fantastic!) scripting language!
Method redefinition is there. For that matter, you invoke the compile on the fly (see the section on "Dynamic Message Calling/Compiling" down near the bottom of the notes).

I understand.

so unlike Java, Smalltalk methods (messages) are 'compound'.
ifTrue: and ifTrue: ifFalse: and ifFalse: are difference messages. In Java we have one method receiving multiple parameters, in Smalltalk the message itself organizes it. Cool. I can see it's a pretty neat language design.

Post formatting

Hello Chris, it would be nice if you would reformat that long "pre" line so that it does not make the page width so large... Thanks!

Reformatted

Broke it up into some more lines (and fixed it to use the standard smalltalk symbols for message selectors).

the *ideas* behind

the *ideas* behind Smalltalk
Design Principles Behind Smalltalk

  • classes are first-class objects? whatever does that mean?
    It means that each class is itself an object which is an instance of a metaclass, and a metaclass is itself an object ...
  • the difference between 'self' and 'this' (in Java)?
    Why would you use 'this' in Java?
    Why would you use 'self' in Smalltalk?
  • isn't Smalltalk dynamically typed? how do classes interact with dynamic typing?
    How do numbers and strings interact with dynamic typing in other dynamically type checked languages?
  • does currying have a Smalltalk counterpart?
    Is there a way to represent functions (rather than methods) in Smalltalk?
  • why do people call Smalltalk "pure OO"? apart from the superficial primitive types in Java, aren't everything else objects?
    It makes a nice slogan. In Java - are classes objects, are methods objects, is the compiler an object, ...
  • interfaces? do they make sense?
    Do they make sense in Java or Smalltalk? Adding Dynamic Interfaces to Smalltalk
  • is there any intuitive reflection mechanism in Smalltalk?
    Smalltalk: a Reflective Language
    Reflective Facilities in Smalltalk-80

Kudos!

This is probably *exactly* what I needed to know. The diagrams were crystal clear. Funny, two days of googling failed to locate that page! I should pick my keywords more thoughfully.

(or may be it's just because I didn't know the term 'metaclass')

Is there a way to represent functions (rather than methods) in Smalltalk?
Apart from this one, your Socratic method was working quite well :-| But for this one, I just don't know! Code blocks? Can a code block take another code block as an argument?

But actually I am not really after currying. I am after a functional semantics of multiple message passing.

Hmm. Makes you think, doesn't it? What exactly is "advancement"? As of today, I see three closely related interpretations, procedural, functional, and object-oriented (quite neatly covered by Perl, Haskell and Smalltalk, the choice of representatives chosen to be a bit shocking, or should I say Turing Machines, Lambda Calculus and Petri nets respectively?), and the sad part is that new languages are mostly error-correcting. This is bad. Never mind me.

purity reminds me of the X-Files

uchchwhash: But I want to know why Smalltalk is the definitive OO language.

I often heard that characterization during the early 90's as a way of contrasting Smalltalk with C++, since in C++ one could still program in C style with non-virtual methods and with visibility into member variables outside an object. In Smalltalk, you could only interact with an object through it's interface, which was always "virtual" and late-binding, so you could always substitute another object that obeyed the same API. This focus make Smalltalk seem more definitively oo because you weren't permitted to make non-oo choices in the name of efficiency or (obsessive?) cost avoidance.

uchchwhash: classes are first-class objects? whatever does that mean? examples?

This use of "first class" usually means a variable can have a value of the sort mentioned. So in Smalltalk, you can have a variable whose value is a class instance, so the class is a thing you can do something to at runtime, such as ask it which methods it understands.

In contrast, C++ doesn't have "first-class" classes in the same sense. If you define a class Foo, you can make instances of Foo, but you can't have a value that is the Foo class itself so you can perform operations on Foo itself.

uchchwhash: the difference between 'self' and 'this' (in Java)?

Those are very analogous. Under C++, 'this' is the reserved keyword that only refers to the instance of the class passed implicitly to the current class whose method is being defined. Under Smalltalk, the 'self' keyword means almost exactly the same thing -- it's predefined to mean the instance of the class passed to the method being defined. (The 'super' keyword is used to mean the same thing as 'self' except messages start dispatching with the superclass; C++ does this by naming a superclass specifically at the point where you invoke the method.)

uchchwhash: isn't Smalltalk dynamically typed? how do classes interact with dynamic typing?

Yes, in the sense Smalltalk usually uses "duck typing" which means if an object can understand the message you want to send it, you can do so even if you have no idea what class is involved. The phrase "dynamic typing" tends to be slightly under dispute since it can be used to mean different things. Even saying this much can spur a new random static vs dynamic typing argument. (Please, don't. :-)

Under Smalltalk, every object has a class. This means you can send the "class" message to any value, and you'll get a value back which is the class for that value, where this class is a "first-class" runtime representation of the class -- one you can ask questions at runtime like any other object.

Classes in Smalltalk interact with dynamic typing as per the definition of method dispatch in Smalltalk, which more or less says sending an object a message means getting the object's class (or superclass if you start with 'super' instead of 'self', when the target object is 'self') and finding the method associated with that message, where the closest definition in the class hierarchy takes precedence (ie, method overriding happens because subclass method definitions shadow those of superclasses).

uchchwhash: both functional languages and Smalltalk exhibit 'minimal' syntax in a sense, am I right? why? how?

I don't think minimal syntax was espoused very often as a very intentional aspect of Smalltalk design; I rarely saw that said anywhere when I started reading about Smalltalk years ago. But Smalltalk syntax happens to be very minimal in the sense that the grammer is very unambiguous, to the extent ascii characters tend to get used for only one sort of meaning. You can write a parser for blue book Smalltalk with one token lookahead, if I remember right.

I guess the idea was that everything you wanted to get done was mediated by sending messages. You didn't need more kinds of syntax because you could encode everything you meant in message sending syntax. This even applied to things like blocks of 'if' expressions, which were statically inlined by the compiler rather than performing really performing the dynamic runtime lookup dispath implied by the syntax.

(Smalltalk did not -- but could have -- use message sending syntax for method definition itself. Methods are defined declaratively, with little delimiting markup. But Smalltalk might have defined, eg, a symbol that meant "the compiler", and method definition could have been a message to the compiler saying "here's a method I want you to define". Not that this would be a great idea; it just illustrates you can encode most things you want done as a request for some entity somewhere to do it for you. It can always be compiled into something else.)

uchchwhash: why do people call Smalltalk "pure OO"? apart from the superficial primitive types in Java, aren't everything else objects? what does it mean to be "pure OO"?

Folks tend to use "pure oo" to mean a language where you can't have non-object values. If you have any primtive types (like ints) that are not objects, then those are exceptions to an oo focus.

uchchwhash: interfaces? do they make sense?

Interfaces are a form of static typing for "duck typing" style dynamic dispatch. If Smalltalk required type declarations for variables, they would be "interface" style as long as duck typing was the rule.

uchchwhash: is there any intuitive reflection mechanism in Smalltalk?

Smalltalk has reflection in the sense you can ask objects at runtime what they understand. Whether the API is intuitive depends on how you like the interface.

C++

Thanks for your reply. I found your examples involving C++ particularly helpful. By now, I guess I have a pretty good idea about what to look for. The question remains as to where to look for it.

Perhaps you could point me to some place where subclassing in Smalltalk is contrasted with Java's? Your explanation sounded quite alien (for a Java-savvy), I'm afraid. Can I apply this/self correspondence to super/super correspondence with confidence? Or will be it the 'biggest mistake of my life'?

Cheers and take care.

Java and Smalltalk syntax

message syntax to runtime method dispatch

uchchwhash: Perhaps you could point me to some place where subclassing in Smalltalk is contrasted with Java's? Your explanation sounded quite alien (for a Java-savvy), I'm afraid.

(Please forgive my use of stream-of-conscious format instead of reverse pyramid structure as if I was writing something for publication.)

I'm not Java savvy enough to do a decent job. And if I was, I'd hate to explain Smalltalk subclassing in terms of something more complex. It might be better if I just describe matters in terms of hash tables using symbols as keys. (Smalltalk symbols are like Lisp symbols: interned strings such that two symbols with the same name are in fact identically the same symbol instance. If string 'foo' is interned as a symbol, then #foo is this symbol under Smalltalk and 'foo is this symbol under Lisp.) The explanation will also sound pretty much like the way Python method dictionaries are done, so you can read about Python and get more or less the same description.

My explanation below relates what you see lexically in the grammar to what you're likely to find in the runtime data structures of resulting Smalltalk classes.

Each Smalltalk class has a method dictionary containing ordered pairs of (selector, method) entries. The method value has a type something like CompiledMethod, or whatever a particular runtime wants. The selector key has type Symbol, where a symbol is an interned string as noted above. Every time a method is defined, an entry is added to a class method dictionary with the method name as the key, and the compiled method as the value.

The term "selector" in Smalltalk means a symbol used as the name of a method, and nothing more. So if you add a unary method named 'negate' to some class, then #negate is the symbol used as the selector for that method. Selectors only fall into three classes, depending on letters in the name, corresponding to the three grammatically different ways to express a message send in Smalltalk: keyword, binary, and unary messages. (This is in order of increasing precedence.) Keyword selectors end in colons. Binary selectors are one or two special symbols from an explicit list. Unary selectors are alphanumer identifiers that don't end in colon. The arity of a unary method is one. The arity of a binary method is two. And the arity of a keyword method is one plus the number of colons that appear in the selector name. (Plus one is for the message's receiver.)

I just summarized what you can see yourself from the original Smalltalk grammar bubble diagrams, if you work out the consequences of the resulting grammar. Here I'll blockquote a sidebar on bubble diagrams:

If you buy a physical copy of one of the original Smalltalk books, the inner hardback cover is decorated with bubble diagrams covering the entire Smalltalk grammar, which is (to me) shockingly simple. I believe this is the way Smalltalk's grammar was presented to early users. (Its's fairly easy to translate the bubble diagrams into standard BNF notation, but perhaps few of the early non-technical users would have understood this notation.)

Just now I googled for "smalltalk grammar bubble diagrams" and found this page:

http://www.cs.ualberta.ca/~duane/courses/625/parser/

It has all the original Smalltalk bubble diagrams as jpegs apparently scanned from the book. But you'd best save your own local copy, since I don't see very many other hits for this material. Maybe it will vanish by the time folks read this post later.

To illustrate method dispatch, and resulting style of Smalltalk subclassing, let's consider an example. Earlier in this thread you chose the following example Smalltalk statement:

y := x indexOf: $e ifAbsent: [0].

This assigns to variable y the value returned from sending #indexOf:ifAbsent: to x, with two arguments, the character constant $e and block [0]. (Note the purpose of using a block is delayed evaluation; the only way to avoid evaluating expressions passed to a method is to put them in a block, so they won't be evaluated until someone evaluates the block.)

So your example here dispatches only one message: a keyword message named #indexOf:ifAbsent: taking two arguments plus the receiver x. (Smalltalk grammar intersperses the arguments with each section of a keyword message selector name, so a one to one corresponence results.)

When you evluate the right-hand-side, what happens is something like this. The method to be called is found by the runtime by evaluating something like the following:

(x class) methodForSelector: #indexOf:ifAbsent:

(Note I just made up the methodForSelector: name here; it's just pseudocode.) The method returned by that expression is then called with two arguments $e and [0].

A Smalltalk compiler will typically emit bytecode that actually references symbol #indexOf:ifAbsent: as a literal value in the method dispatch (unless the bytecode itself encodes the selector). So the method is effectively dispatched by name. This symbol is used as a lookup key to search method dictionaries -- presumably hash tables -- starting with the class of x and working back to superclasses of (x class) if #indexOf:ifAbsent: is not found in (x class). Each class has a pointer to it's own superclass, so searching the inheritance chain at runtime is explicit.

In practice a runtime won't want to actually search the inheritance chain of classes every time a method is dispatched, but this is easily avoided by using a lookaside cache containing the result of earlier similar dispatches. A lookaside cache might just be a large hash table with keys of format (class, selector) and values equal to methods found earlier for such searches. (Lookaside cache invalidations need only occur when new methods are added to class method dictionaries.)

This sort of dispatch and this kind of lookaside cache is often used in other similar languages like Objective C, which imitates both Smalltalk syntax and Smalltalk style method dispatch using selectors. Except Objective C probably maps selector names to integer constants at compile time, rather than using the symbols for selectors themselves. (I seem to recall having a conversation with John Anderson about this when we worked together briefly at OSAF. He was the guy who worked on optimizations in the Objective C runtime at NeXT, and he'd done something like the same lookaside cache that I'd coded into a Smalltalk I'd done in the 90's.)

Anyway, you can infer the nature of Smalltalk subclassing from a few details:

  • each class has an array of member variables keyed by name/position
  • each class has a table of methods keyed by selector
  • each class declares it's own superclass when it is defined
  • every non-primitive object has a pointer to it's own class
  • (the class of every primitive type is known statically by the runtime)

Subclassing under Smalltalk just involves naming the superclass (or superclasses when multiple inheritanced is supported). Method overriding merely requires redefining a method with the same selector. The entry in the method dictionary of a subclass will be found first at dispatch time, so any other entries for the same selector in superclasses won't be found.

Smalltalk-80 didn't have private scopes for member variables, so all subclasses could see and use the members of any superclass. Using C++ terminology, all Smalltalk methods were public and all member variables were protected.