Beginner

Variables and Types in Smalltalk

Learn about variables, data types, and Smalltalk pure object model - from integers and strings to symbols, characters, and type introspection

In Smalltalk, every value is an object — integers, floats, booleans, even nil and true. There are no primitive types, no special cases. This purity makes Smalltalk’s type system remarkably consistent: to find out what something is, you just ask it.

Variables in Smalltalk are dynamically typed. You declare them by name — with no type annotation — and assignment uses :=. The language is strongly typed (you cannot silently coerce a number into a string), but the type of a variable can change at runtime simply by assigning a different object to it.

In this tutorial, you will see how Smalltalk handles basic types (integers, floats, strings, booleans), Smalltalk-specific types (symbols, characters, arrays, nil), and type conversions — all through the lens of message passing.

Declaring Variables

In GNU Smalltalk scripts, variables are declared at the top with the | varName | syntax. Multiple variables can share one declaration block. Assignment uses :=. Each statement ends with . (the period is a statement separator, so the last statement may optionally omit it).

Create a file named variables_basic.st:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
| count price greeting active |
count := 100.
price := 19.95.
greeting := 'Hello, Smalltalk'.
active := true.

Transcript show: 'count = '; show: count printString; cr.
Transcript show: 'price = '; show: price printString; cr.
Transcript show: 'greeting = '; show: greeting; cr.
Transcript show: 'active = '; show: active printString; cr.
Transcript show: 'count class = '; show: count class name; cr.
Transcript show: 'price class = '; show: price class name; cr

This example demonstrates Smalltalk’s core types:

  • SmallInteger — Integer values that fit in a machine word. For arbitrarily large integers, Smalltalk automatically promotes to LargePositiveInteger or LargeNegativeInteger.
  • FloatD — Double-precision floating-point. In GNU Smalltalk, float literals like 19.95 are instances of FloatD (double). FloatE and FloatQ cover single and quad precision.
  • String — A sequence of characters, delimited by single quotes. (Double quotes are comments in Smalltalk, not strings.)
  • True / Falsetrue and false are singleton instances of the classes True and False, both subclasses of Boolean.

The class message asks any object which class it belongs to. The name message then returns that class name as a String. This is Smalltalk reflection in its simplest form — every object knows its own type without any special operator or keyword.

Smalltalk-Specific Types

Beyond the basics, Smalltalk has several types that are central to the language’s character: symbols, characters, arrays, and nil.

Create a file named variables_types.st:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
| lang initial digits nothing |
lang := #smalltalk.
initial := $S.
digits := #(1 2 3 4 5).
nothing := nil.

Transcript show: 'Symbol: '; show: lang printString; cr.
Transcript show: 'Character: '; show: initial printString; cr.
Transcript show: 'Array: '; show: digits printString; cr.
Transcript show: 'nil: '; show: nothing printString; cr.
Transcript cr.
Transcript show: 'Symbol class: '; show: lang class name; cr.
Transcript show: 'Character class: '; show: initial class name; cr.
Transcript show: 'Array class: '; show: digits class name; cr.
Transcript show: 'nil class: '; show: nothing class name; cr

Symbols

A Symbol (#name) is an interned, immutable identifier. Any two symbols with the same name are guaranteed to be the identical object in memory — #foo == #foo is always true. Symbols are used extensively as method selectors, dictionary keys, and enumeration-like constants. They respond to most String messages but cannot be modified.

Characters

A Character ($A, $x, $!) is a single-character object created with the $ prefix. Characters are not strings — they are their own class and respond to messages like asInteger (returns the ASCII code), asUppercase, asLowercase, and isLetter.

Array Literals

#(1 2 3 4 5) creates a fixed-size, ordered Array at parse time. Elements are separated by spaces, not commas. For a resizable collection, use OrderedCollection new instead. Individual elements are accessed with at: (one-based indexing):

1
2
3
| arr |
arr := #(10 20 30).
Transcript show: (arr at: 2) printString; cr

This would print 20.

nil

nil is the sole instance of UndefinedObject. It represents the absence of a meaningful value. Unlike null in many languages, nil is a full object — it responds to messages. Uninitialized variables hold nil by default.

Type Conversions

Smalltalk’s strong typing means conversions are always explicit: you send a conversion message to an object and receive a new object of the target type.

Create a file named variables_convert.st:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
| n f s |
n := 42.
f := 3.14.
s := '100'.

Transcript show: 'Integer to float: '; show: n asFloat printString; cr.
Transcript show: 'Float truncated: '; show: f truncated printString; cr.
Transcript show: 'Float rounded: '; show: f rounded printString; cr.
Transcript show: 'Integer to string: '; show: n printString; cr.
Transcript show: 'String to integer: '; show: s asInteger printString; cr.
Transcript show: 'Integer to character: '; show: n asCharacter printString; cr

Common conversion messages:

MessageEffectExample
asFloatInteger → FloatD42 asFloat42.0
truncatedFloat → Integer (toward zero)3.9 truncated3
roundedFloat → nearest Integer3.5 rounded4
printStringAny object → String representationtrue printString'true'
asIntegerString → Integer'99' asInteger99
asCharacterInteger → Character (by ASCII code)65 asCharacter$A

Nothing is coerced silently. If you send a message that expects a type the object does not conform to, you get a MessageNotUnderstood error at runtime — not a quiet incorrect result.

Running with Docker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Pull the GNU Smalltalk image
docker pull sl4m/gnu-smalltalk:latest

# Run the basic variables example
docker run --rm -v $(pwd):/app -w /app sl4m/gnu-smalltalk:latest gst variables_basic.st

# Run the Smalltalk-specific types example
docker run --rm -v $(pwd):/app -w /app sl4m/gnu-smalltalk:latest gst variables_types.st

# Run the type conversions example
docker run --rm -v $(pwd):/app -w /app sl4m/gnu-smalltalk:latest gst variables_convert.st

Expected Output

variables_basic.st:

count = 100
price = 19.95
greeting = Hello, Smalltalk
active = true
count class = SmallInteger
price class = FloatD

variables_types.st:

Symbol: #smalltalk
Character: $S
Array: (1 2 3 4 5 )
nil: nil

Symbol class: Symbol
Character class: Character
Array class: Array
nil class: UndefinedObject

variables_convert.st:

Integer to float: 42.0
Float truncated: 3
Float rounded: 3
Integer to string: 42
String to integer: 100
Integer to character: $*

(ASCII code 42 is the * character.)

Key Concepts

  • No type declarations — Variables are declared by name only (| x |). The type is determined entirely by the object currently assigned to the variable.
  • Assignment uses := — The colon-equals operator is unambiguous and avoids confusion with the equality test message =.
  • Every value is a full object — There are no primitive types anywhere. 42 is a SmallInt, true is an instance of True, nil is an UndefinedObject. Each responds to messages.
  • Symbols are interned — Any two #name literals with the same spelling are the exact same object. This makes symbol identity comparison (==) both correct and efficient for use as dictionary keys or selectors.
  • Characters use $ prefix$A is the Character object for the letter A. It is not a single-character string and does not use quotes.
  • Type introspection is message sendinganObject class name retrieves the class name of any object. There is no typeof keyword or special reflection API — it is just messages all the way down.
  • Conversions are explicit messagesasFloat, asInteger, truncated, rounded, printString, and asCharacter are regular messages. No implicit coercion occurs.
  • nil is a real object — Unlike null in many languages, nil responds to messages. Uninitialized variables default to nil, and sending an unrecognized message to nil raises a MessageNotUnderstood error rather than crashing silently.

Running Today

All examples can be run using Docker:

docker pull sl4m/gnu-smalltalk:latest
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining