Beginner's Guide to Smalltalk

  ·   17 min read

Introduction to Smalltalk #

What is Smalltalk? #

Smalltalk is a dynamically typed, reflective, object-oriented programming language. Unlike many languages that evolved from a design document, Smalltalk emerged from a research project at Xerox PARC in the 1970s, aiming to create a truly object-oriented system. Everything in Smalltalk is an object, including classes, methods, and even the code itself. This results in a highly consistent and elegant programming model. Smalltalk emphasizes live coding, with immediate feedback on code changes, allowing for rapid prototyping and experimentation. Its image-based persistence means the entire system’s state is saved and restored, providing a seamless development experience.

Why Learn Smalltalk? #

Learning Smalltalk offers several advantages:

  • Deep understanding of OOP: Smalltalk’s pure object-oriented nature provides a strong foundation for understanding object-oriented principles. This understanding can translate to working with other object-oriented languages more effectively.
  • Improved Programming Skills: Smalltalk’s emphasis on simplicity and elegance promotes good programming practices and design patterns. It encourages the development of clean, well-structured code.
  • Rapid Prototyping: The live coding and immediate feedback features make Smalltalk ideal for rapid prototyping and exploratory programming.
  • Image-based Persistence: The ability to save and restore the entire development environment significantly speeds up the development cycle.
  • Active Community: Although not as large as some other languages, the Smalltalk community is active and supportive, offering resources and assistance to learners.

Smalltalk Dialects and Implementations #

Several dialects and implementations of Smalltalk exist, each with its own strengths and characteristics. The most popular include:

  • Pharo: A modern, open-source Smalltalk environment focused on ease of use and rapid development. It’s known for its excellent tooling and vibrant community.
  • Squeak: Another open-source implementation, Squeak is particularly popular for educational purposes and multimedia applications. It has a strong emphasis on image-based programming and interactive media.
  • GNU Smalltalk: An open-source implementation that prioritizes standards compliance and portability.

Choosing an implementation often depends on personal preference and project requirements. For beginners, Pharo is generally recommended due to its user-friendly interface and comprehensive documentation.

Setting up your Smalltalk Environment (Pharo, Squeak, GNU Smalltalk) #

Setting up your Smalltalk environment is relatively straightforward. The process generally involves downloading the desired implementation and running the installer.

Pharo:

  1. Download the latest Pharo image from the official Pharo website.
  2. Run the downloaded image (usually a .image file).
  3. The Pharo image will launch in a new window, providing access to the development environment.

Squeak:

  1. Download the latest Squeak image from the official Squeak website.
  2. Run the downloaded image.
  3. The Squeak image will launch, presenting a similar development environment to Pharo.

GNU Smalltalk:

  1. GNU Smalltalk typically requires more manual installation steps, possibly involving package managers such as apt or yum (depending on your operating system). Consult the GNU Smalltalk documentation for platform-specific instructions. It might involve compiling source code.
  2. After installation, run the Smalltalk environment.

Once your chosen environment is running, you’ll have access to the integrated development environment (IDE), which includes a code editor, debugger, and other tools necessary for Smalltalk development. Explore the environment and familiarize yourself with its features before beginning to write code. Remember to refer to the official documentation for your chosen Smalltalk implementation for detailed instructions and troubleshooting.

The Smalltalk Image #

Understanding the Image #

The Smalltalk image is a fundamental concept, differentiating it from many other programming languages. It’s not just a compiled program; it’s a persistent snapshot of the entire Smalltalk environment’s state. This includes:

  • The system’s classes and methods: The core Smalltalk libraries and any custom classes you’ve defined.
  • The objects currently in memory: All variables, data structures, and objects created during your session.
  • The state of the system: The current execution context, breakpoints, and other runtime information.

This image-based approach allows you to save your work, including all code and data, and resume your session exactly where you left off. No compilation step is needed to run your code; the image contains the code already compiled and ready to execute. It’s the Smalltalk equivalent of saving the entire development environment.

Working with the Workspace #

The workspace is a powerful tool within the Smalltalk image. It acts as an interactive code editor and interpreter, allowing you to experiment with Smalltalk code directly and see immediate results. You type in expressions or statements, and pressing the “Do it” button (usually represented by a right-pointing arrow or similar icon) executes the code. The results are displayed immediately below your code, often including the value of the last evaluated expression. The workspace is invaluable for quick testing, exploring objects, and experimenting with new code snippets without the need to create a separate file or class.

Inspecting Objects #

Smalltalk provides a sophisticated object inspector. This allows you to examine the internal structure of any object in detail. By selecting an object and choosing the “inspect” option (usually through a right-click menu or a dedicated inspector button), a window opens displaying the object’s class, its instance variables, and their values. You can drill down into the values of instance variables if they are themselves objects, recursively inspecting their contents. This deep inspection is vital for debugging and understanding how objects interact within the system. It helps you follow data flow and pinpoint the source of errors.

Saving and Loading Images #

Saving and loading Smalltalk images is crucial for preserving your work. The process involves saving the entire system’s state—code, data, and execution context—into a file (typically with a .image extension). This image file can be loaded later to resume your development session exactly where you left off.

Saving: The exact method to save an image varies slightly between Smalltalk implementations, but typically involves a menu command within the IDE (e.g., “Save Image” or similar). You will be prompted to choose a filename and location to save the image file.

Loading: Loading a previously saved image is typically achieved through a menu option (e.g., “Open Image” or “Load Image”). You select the saved .image file, and Smalltalk will restore the entire state from that file, including your code, objects, and the execution context at the time of saving. This eliminates the need to recompile or restart the entire environment. This feature makes Smalltalk’s development workflow exceptionally productive.

Fundamental Concepts #

Objects and Messages #

In Smalltalk, everything is an object. An object encapsulates data (instance variables) and behavior (methods). Objects interact by sending each other messages. A message is a request for an object to perform a specific action. For example, 3 + 4 is not an arithmetic operation in the traditional sense; it’s a message (+) sent to the object 3, with 4 as an argument. The 3 object responds to this message by returning the result 7. This message-passing paradigm is central to Smalltalk’s design.

Classes and Instances #

A class is a blueprint or template for creating objects. It defines the structure (instance variables) and behavior (methods) of the objects it creates. An instance is an object created from a class. Many instances can be created from a single class, each having its own set of instance variable values. For example, the class Rectangle might define instance variables like width and height, and methods like area and perimeter. Multiple Rectangle instances can exist, each with different width and height values.

Methods and Method Invocation #

A method is a piece of code that defines an object’s behavior in response to a message. Method invocation is the act of sending a message to an object, triggering the execution of the corresponding method. The syntax in Smalltalk is straightforward: object messageArguments. For example, to calculate the area of a rectangle instance named myRectangle, you would send it the area message: myRectangle area. If the area method requires arguments, those would be included in the message send, for example: myRectangle displayOn: aCanvas.

Variables and Data Types #

Smalltalk is dynamically typed, meaning you don’t explicitly declare the data type of a variable. The type is determined at runtime. There are several fundamental data types:

  • Numbers: Integers, floating-point numbers.
  • Booleans: true and false.
  • Characters: Single characters, represented by single quotes, like $'A'.
  • Strings: Sequences of characters, represented by single quotes, like 'Hello'.
  • Arrays: Ordered collections of objects. Created using #(...), e.g., #(1 2 3 4).
  • Dictionaries: Collections of key-value pairs.
  • Symbols: Unique identifiers, often used as keys in dictionaries and in other contexts where a constant needs to be used.

Variables are assigned values using the := operator. For example, myVariable := 10.

Control Structures (if, while, etc.) #

Smalltalk employs various control structures to manage program flow:

  • Conditional Statements: ifTrue: ifFalse: and ifTrue: These handle conditional execution based on boolean values. For example: condition ifTrue: [ ...code to execute if true... ] ifFalse: [ ...code to execute if false... ]. A simpler version exists if only actions for true values are required.

  • Loops: whileTrue: executes a block of code repeatedly as long as a condition evaluates to true. timesRepeat: repeats a code block a specified number of times. Collections also provide methods for iteration like do: that efficiently iterate over each element.

  • Blocks: Blocks are anonymous code blocks surrounded by square brackets [ ...code... ]. They can be passed as arguments to methods, allowing for flexible and powerful control flow.

Smalltalk’s syntax for these structures emphasizes readability and conciseness, using keywords and message sending instead of complex syntax found in some other languages.

Working with Classes and Objects #

Creating New Classes #

Creating a new class in Smalltalk involves defining its structure and behavior. This is typically done through the Smalltalk IDE’s class browser. You’ll define a new subclass of an existing class, inheriting its properties and adding your own. The process generally involves specifying the superclass (the class from which the new class inherits) and declaring instance variables. For example, to create a Circle class that inherits from a Shape class, you’d add a new subclass entry in the class browser, specifying Shape as the superclass. The exact steps might vary slightly depending on the Smalltalk environment (Pharo, Squeak, etc.), but they usually involve a graphical user interface for manipulating class definitions.

Defining Methods #

Methods define the behavior of objects. They are added to a class within the class browser. A method consists of a method name (selector), a list of arguments (if any), and a body of code that specifies its functionality. For example:

area
    ^ self width * self height 

This area method calculates the area of a rectangle by multiplying its width and height. The ^ symbol indicates that the value following it is the result returned by the method. The self keyword refers to the object the method is called on.

Instance Variables #

Instance variables are data associated with each instance of a class. They hold the specific state of an object. Instance variables are declared within the class definition, often in a dedicated section of the class browser. For example, a Rectangle class might have instance variables such as width and height. Each instance of Rectangle will have its own width and height values. Access to instance variables usually happens via accessor methods (e.g., width and width:) which provide an organized interface.

Class Variables #

Class variables hold data shared by all instances of a class. They are declared using class within the class definition. Unlike instance variables, there is only one copy of a class variable for the entire class. They are typically used for shared resources or constants associated with the entire class rather than with individual instances. Access to class variables is typically done via class methods.

Inheritance and Polymorphism #

Smalltalk strongly supports inheritance and polymorphism. Inheritance allows you to create new classes (subclasses) based on existing classes (superclasses), inheriting their methods and instance variables. Subclasses can override inherited methods to provide specialized behavior and add their own methods. Polymorphism means that objects of different classes can respond to the same message in different ways. For example, both Circle and Rectangle might have an area method, but each would implement it differently to calculate the area appropriately for its shape. This capability leads to highly flexible and extensible code. This is often utilized through abstract classes that define the interface and concrete subclasses that define specific implementations.

Common Smalltalk Tasks #

Creating and Manipulating Collections #

Smalltalk provides a rich set of collection classes for managing groups of objects. The most common are:

  • Arrays: Ordered collections of objects, accessed by index. Created using #(1 2 3) or Array with: 1 with: 2 with: 3. Methods like at:, at:put:, size, and indexOf: are commonly used.

  • OrderedCollections: Similar to arrays, but allow adding and removing elements efficiently anywhere in the collection.

  • Sets: Unordered collections of unique objects. Useful for checking membership and eliminating duplicates.

  • Dictionaries: Collections of key-value pairs, offering fast lookups using keys. Created using Dictionary new. Methods like at:, at:put:, keys, and values are useful.

  • Bags: Collections where elements can be repeated; useful for counting element occurrences.

Many collection classes share common protocols (interfaces) for operations such as adding, removing, and iterating over elements. Smalltalk’s collection library is highly versatile and provides efficient methods for various data manipulation tasks.

Working with Strings and Numbers #

Smalltalk offers powerful built-in methods for string and number manipulation:

Strings: String manipulation is achieved through messages such as size, at:, copyReplaceAll:with:, substringFrom:to:, contains:, findString:, asUppercase, asLowercase, asNumber etc. These methods allow easy concatenation, substring extraction, searching, and conversion.

Numbers: Basic arithmetic operations (+, -, *, /) are supported directly, along with more advanced mathematical functions available through the Number class or specialized subclasses such as Integer and Float. Methods like abs, sqrt, round, floor, and ceiling are common. String-to-number conversions are easily performed with methods like asNumber.

File I/O #

Smalltalk provides a straightforward way to perform file I/O:

Reading a file: The FileStream class provides methods like newFileNamed:read:, readAll, and similar, allowing you to read the entire file contents into a string or perform line-by-line reads.

Writing to a file: FileStream also provides methods such as newFileNamed:writeStream which allows you to create a stream and write text or data to a file. nextPutAll: is a common message for writing strings. Remember to close the stream after writing using close.

Error handling is crucial during file I/O. Use try...catch blocks to handle potential exceptions like file not found.

GUI Programming Basics (using Morphic or other GUI frameworks) #

Smalltalk’s Morphic framework (or other frameworks like VisualWorks’s) offers a relatively simple way to create graphical user interfaces. Building a simple window often involves:

  1. Creating a window: This might involve creating a WindowMorph, Morph or a similar class.

  2. Adding submorphs (controls): Buttons, text fields, and other UI elements are added as submorphs to the main window morph.

  3. Handling events: Event handlers are defined to respond to user interactions (button clicks, text input).

  4. Layout management: Positioning and arranging UI elements usually utilizes layout mechanisms within the framework.

Different Smalltalk environments may have slightly different approaches, but the general principles are the same: building the UI through a hierarchy of graphical objects and defining event handlers to respond to user actions.

Simple Example Applications #

Simple applications could include:

  • A calculator: A simple calculator demonstrating number operations and UI interaction.

  • A text editor: A rudimentary editor for opening, editing, and saving text files.

  • A drawing application: Allow users to draw simple shapes on the screen.

These examples would showcase creating classes, defining methods, handling user input, and implementing basic file I/O and GUI elements, integrating the concepts described in previous sections. Beginners should start with very simple applications to build confidence and understanding. Incrementally adding features to a simple application offers effective learning.

Advanced Topics (Optional) #

Metaclasses #

In Smalltalk, classes are themselves objects. The class of a class is called a metaclass. This allows for powerful metaprogramming capabilities. You can inspect and modify the behavior of classes at runtime by working with their metaclasses. Understanding metaclasses is crucial for advanced techniques like creating custom class methods, modifying class behavior dynamically, and implementing sophisticated class-level functionality. They offer a powerful layer of abstraction for manipulating the class system itself.

Blocks and Closures #

Blocks are anonymous code blocks delimited by square brackets [ ... code ... ]. They are first-class objects that can be passed as arguments to methods and returned as results. A closure is a block that has access to variables from its surrounding context even after that context has ended. This allows for powerful techniques such as creating iterators, callbacks, and higher-order functions. Blocks enhance code modularity and expressiveness.

Reflection and Introspection #

Smalltalk has strong reflection and introspection capabilities. Reflection refers to the ability of a program to examine and modify its own structure and behavior at runtime. Introspection is the ability to examine the state of an object, including its class, instance variables, and methods. These features allow you to build tools for debugging, code analysis, and dynamic code generation. You can examine the type of an object, get a list of its methods, and even change the value of its instance variables at runtime.

Design Patterns in Smalltalk #

Many common design patterns are naturally expressed in Smalltalk due to its object-oriented nature and flexible mechanisms. Some patterns, like the Model-View-Controller (MVC) pattern, are commonly used in Smalltalk GUI frameworks. Understanding design patterns like MVC, Strategy, Observer, and others can help in writing more modular, reusable, and maintainable Smalltalk code. The elegance of Smalltalk often leads to simpler implementations of these patterns compared to other languages.

Unit Testing and Debugging #

Smalltalk environments often include powerful tools for unit testing and debugging. Unit testing frameworks, like SUnit, allow you to write tests that verify the behavior of individual methods and classes. Smalltalk’s dynamic nature makes debugging straightforward; you can pause execution, inspect the values of variables, and step through code line by line. The debugger is typically integrated into the IDE and provides tools for setting breakpoints, stepping through code, and examining the call stack. The interactive nature of Smalltalk makes debugging intuitive, as changes can be tested and applied directly within the running system. Many Smalltalk environments have integrated debuggers that offer rich functionality for inspecting objects and executing code interactively.

Further Learning and Resources #

Online Tutorials and Documentation #

Numerous online resources are available for learning Smalltalk:

  • Pharo Consortium Website: The official website for Pharo contains tutorials, documentation, and examples. It’s an excellent starting point for learning Pharo-specific aspects.

  • Squeak SourceForge Page: The Squeak project also maintains documentation and tutorials on its SourceForge page.

  • GNU Smalltalk Documentation: The GNU Smalltalk project provides documentation on its implementation.

  • Various Blogs and Articles: Many individual developers and enthusiasts maintain blogs and articles covering various aspects of Smalltalk programming and its applications. Searching for “Smalltalk tutorial” or “Smalltalk Pharo tutorial” will yield many relevant results.

Books on Smalltalk #

Several books offer comprehensive coverage of Smalltalk:

  • “Pharo by Example”: A practical guide to Pharo, focusing on hands-on learning.

  • “Smalltalk-80: The Language and its Implementation”: A classic text providing a deep dive into the language, although it might be more suitable for experienced programmers.

  • “Advanced Programming in Smalltalk”: Offers in-depth coverage of advanced techniques.

Many older books on Smalltalk exist; however, their relevance might be diminished depending on the specific implementation you’re using (e.g., Pharo, Squeak). Look for more recent publications specifically mentioning your chosen Smalltalk environment.

Smalltalk Communities and Forums #

Engaging with the Smalltalk community can provide valuable assistance and insights:

  • Pharo Mailing Lists and Forums: Pharo has active mailing lists and online forums where developers discuss various topics and offer support.

  • Squeak Mailing Lists and Forums: Similar to Pharo, Squeak also has community forums and mailing lists for users to interact and seek help.

  • Stack Overflow: Although not dedicated to Smalltalk, Stack Overflow can sometimes provide answers to specific Smalltalk questions.

Participating in these communities can greatly benefit your learning experience by providing opportunities for asking questions, sharing knowledge, and collaborating with other Smalltalk developers.

Contributing to Open Source Smalltalk Projects #

Contributing to open-source Smalltalk projects is a valuable way to enhance your skills and give back to the community:

  • Pharo and Squeak Projects: Both projects actively encourage community contributions, offering opportunities to improve the language, its libraries, and its tools.

  • GitHub Repositories: Many Smalltalk libraries and applications are hosted on GitHub, allowing you to explore the code, report bugs, or submit patches.

Contributing to open source provides hands-on experience with real-world projects and fosters valuable collaboration skills. Start with small contributions, such as bug fixes or documentation improvements, and gradually increase your involvement as your skills grow. The contribution guidelines for each project will typically guide you on how to proceed.