Operators in Smalltalk
Learn how arithmetic, comparison, logical, and string operators work in Smalltalk - where every operator is really a message sent to an object
In most languages, operators are baked into the grammar: + is a special symbol the parser knows about, with its own precedence table. Smalltalk takes a radically different view. There are no operators in the traditional sense at all. 3 + 4 is not “apply the addition operator” - it is “send the message + with argument 4 to the object 3.” The integer 3 decides what + means by looking up the method in its class.
This is the natural consequence of Smalltalk’s core idea that everything is an object and every action is a message. Arithmetic, comparison, logical operations, and even string concatenation are all just binary messages - messages whose selector is a symbol like +, <, or , and which take exactly one argument. Because they are ordinary messages, you can define new ones on your own classes and send the same + to numbers, fractions, or collections.
This tutorial covers the four families of “operators” you will use constantly - arithmetic, comparison, logical, and string concatenation - plus Smalltalk’s famously simple precedence rules. Because operators are messages, understanding them is really understanding how messages are sent, which unlocks the rest of the language.
Arithmetic Operators
Arithmetic operators are binary messages sent to number objects. One detail surprises newcomers: dividing two integers with / yields an exact Fraction, not a truncated or floating-point result. Smalltalk keeps numbers exact unless you ask otherwise.
Create a file named operators_arithmetic.st:
| |
Notice 5 negated - negation is a unary message, not a - prefix. And (7 / 2) produces 7/2, an exact Fraction object that knows how to print itself. Sending asFloat to it gives the familiar 3.5.
Comparison Operators
Comparison operators are binary messages that return a Boolean object - either true or false. Note that equality is a single = (Smalltalk uses := for assignment, so there is no clash) and inequality is ~=.
Create a file named operators_comparison.st:
| |
The = message compares value (do these objects represent the same thing), so two strings with the same characters are equal. Smalltalk also has ==, which tests identity (are these the exact same object) - a distinction worth remembering, but = is what you want for comparing values.
Logical Operators
Boolean logic is also message-based. The binary messages & (and) and | (or) always evaluate both sides, while the keyword messages and: and or: take a block as their argument and short-circuit - the block only runs if it is needed. not is a unary message.
Create a file named operators_logical.st:
| |
The , (comma) is the binary message for joining collections, including strings. We use displayNl here instead of printNl so the string prints without surrounding quotes.
Operator Precedence
Here is where Smalltalk is wonderfully (and sometimes shockingly) simple. There is no rich precedence table. There are exactly three levels, always applied left to right:
- Unary messages first (e.g.
factorial,negated) - Binary messages next (e.g.
+,*,<,,) - Keyword messages last (e.g.
raisedTo:,and:)
Crucially, all binary operators share the same precedence - * does not bind tighter than +. Use parentheses when you want conventional math precedence.
Create a file named operators_precedence.st:
| |
The expression 3 + 4 * 5 evaluating to 35 instead of 23 is the classic Smalltalk gotcha. Once you internalize “binary messages go strictly left to right,” it becomes second nature.
Assignment
Smalltalk uses := for assignment, and that is the only assignment operator - there are no compound forms like += or *=. To accumulate a value, you send the arithmetic message and assign the result back.
Create a file named operators_assignment.st:
| |
The | total | declares a temporary variable, and each := rebinds it to a new value.
Running with Docker
Run each example with the GNU Smalltalk image. The gst interpreter reads and evaluates a .st file directly.
| |
Expected Output
operators_arithmetic.st:
10
4
21
7/2
3.5
3
1
256
-5
operators_comparison.st:
true
true
true
false
true
false
true
operators_logical.st:
false
true
false
true
true
Smalltalk
operators_precedence.st:
35
23
27
16
operators_assignment.st:
15
30
Key Concepts
- Operators are messages, not syntax.
3 + 4sends the binary message+to3. Any class can implement+,<, or,, so the same operators work across numbers, fractions, strings, and your own objects. - There are only three precedence levels: unary, then binary, then keyword - each evaluated left to right. All binary operators (
+,*,<,,) share one level, so3 + 4 * 5is35. Reach for parentheses to get conventional math ordering. - Integer division with
/stays exact.7 / 2is theFraction7/2, not3or3.5. Use//for floor division,\\for modulo, andasFloatwhen you want a decimal. - Equality is
=, inequality is~=.=compares value;==compares object identity. Assignment is the separate:=, so there is no==-vs-=confusion as in C-family languages. - Logical
&/|are eager;and:/or:short-circuit because they take blocks ([ ... ]) that only evaluate when needed.notis a unary message. - There are no compound assignment operators. Use
total := total + 5rather thantotal += 5. - Unary messages bind tightest, so
3 + 4 factorialis27(thefactorialruns before the+).
Running Today
All examples can be run using Docker:
docker pull sl4m/gnu-smalltalk:latest
Comments
Loading comments...
Leave a Comment