The object of this chapter is to provide a summary of the essentials of Squeak. It is not possible to teach Squeak here, but it is possible to define it. Squeak, as a version of Smalltalk, is an object-oriented programming system based on the concepts of classes defining object types and what each type can do, in the form of methods. All of Squeak programming consists of sending messages to objects to invoke their methods in sequences controlled by a very simple syntax. This is in strong contrast with imperative procedural programming, where there are few object types that set few restrictions on their use.
All of Squeak is written in Squeak, using circular definitions, but not all of Squeak can be run in Squeak because of those circular definitions. It is necessary to break the circles by defining some things so that they can be translated from Squeak to a language such as C that can be compiled and run on almost any computer.
The Squeak programmer must be able to understand Squeak as defined in the circular version, and also to break the circles in a different way that supports understanding rather than implementation. This can be quite confusing at first. It is not possible to sort the fundamental concepts of Squeak so that one can explain each one referring only to already defined concepts, although it is possible to approximate such an order by giving partial explanations, and returning to each concept with more complete accounts several times over. The account below makes no attempt at such an order. Definitions given here freely refer to concepts defined later on.
Almost everything in Smalltalk generally and Squeak in particular is an object. Objects are defined by their position in the Class hierarchy and by their structure, which defines how they are represented and how actions on objects (methods) are defined. Methods have names called selectors, and program code implementing the methods. Squeak programming consists of sending messages to objects. Messages can be simple selectors by themselves, or selectors combined with expressions. Sending a message invokes some method that returns a result. The rest of the definition of the object system occurs in the Squeak Virtual Machine (VM), which handles details of memory management, implementation of primitive operations, and interpretation of Squeak code. About a hundred methods are implemented as System Primitives in the VM, originally in the machine language of a computer, and later in highly portable C, so that Squeak and thus Etoys can run almost identically on a very wide range of computers.
This chapter explains the visible structure of Squeak as it affects the use of Etoys. Details of Squeak and Smalltalk VMs can be found in other documents listed in the Further Reading appendix.
Nearly everything in Squeak is a member of the class Object or one of the classes derived from it, although some are in an even more basic class called ProtoObject. Different kinds of object are defined as instances of classes. A class is generally defined with
a superclass from which it inherits behavior for its instances
a metaclass that defines the behavior of the class, such as creating new instances.
a category, usually a group of related classes
a name used to identify the class in program code (except that metaclasses are not named, and are instead identified in the form className class for the metaclass of the class named className)
Each of these is another kind of object, built with still other kinds of object. Classes commonly have methods for creating instances, each of which shares the structure defined in the class.
Every class except ProtoObject is defined firstly as a subclass of one other class, its superclass. ProtoObject is a subclass of itself, and is its own superclass. Thus the classes form a rooted tree, starting at ProtoObject. The Class tree can be viewed in the Hierarchy Browser described elsewhere in this manual. Each class inherits the variables and instance methods of its superclass, the superclass of its superclass, and so on up the tree. However, a class can define new methods and override inherited methods with versions more appropriate to the object type it represents. For example, Number defines a set of arithmetic operations, and its subclasses, such as Integer, Fraction, or Float, redefine those operations as necessary for the different kinds of number. The Fraction class also defines methods for accessing the numerator and denominator of a Fraction, methods that would be meaningless for a Float.
The most fundamental operation on any class is creating instances of that class. This is done by sending a message such as new to the class itself. This requires that the class be an instance of another class, which is known as its metaclass. Every ordinary class has a metaclass, and every metaclass has one instance, a single class. Ordinary classes are all named, but metaclasses are not. The metaclass of Float, for example, can only be accessed as
Float class
All metaclasses are instances of Metaclass, and do not themselves have metaclasses. The metaclass
Metaclass class
is both the metaclass of Metaclass, and an instance of Metaclass. This is one of those points of circularity in the definition of Squeak that requires an effort of understanding, and support in the Virtual Machine.
Classes and methods are grouped for the convenience of the programmer and learner into categories and protocols, respectively. These groupings have no other significance. They are used in the System Browser, described elsewhere, to simplify finding related items.
There are several kinds of names in Squeak. One major distinction is between private names, accessible only within one class, shared names accessible among more than one class, and global names accessible within all classes. Private names all begin with lowercase letters, while shared and global names begin with uppercase letters.
It is necessary to have ways of defining and using numbers, characters (usually ASCII or Unicode), and character strings as basic data types. In addition, symbols are defined as a basic type for internal system use.
char:=Character value: 16r0411 wideString := String with: char.
This prints as Russian Cyrillic 'Б'.
All objects created within a given class are instances of that class. They all have the same variable types and the same set of paired selectors and methods, some defined in the class, and some inherited via the superclass chain. Instances can generally be created by a class method, usually new, and can then be assigned to variables, used in expressions, or displayed graphically. Some classes provide other behaviors, such as playing multimedia files. Selectors other than new can be provided for creating instances, and there are abstract classes that have no instances and no method for creating any. Abstract classes are meant to be subclassed, with each subclass defining further behavior and its own method for creating instances.
The behavior of an object is defined by its instance and class methods, which are identified by selectors. Messages made from selectors and in many cases object names and literal constants are sent to objects to request that the object perform some action or calculation, usually returning a result. The combination of a selector with a variable name for each part is called a message pattern. For example, given the selector at:put:, its message pattern could take the form
at: aPosition put: aValue
Methods provide the implementations of selectors. Instance methods are defined to be sent to instances of the class. Class methods are defined in the metaclass of the class, to be sent to the class itself. One of the most common class methods is new, which for many classes requests creation of a new instance of that class.
As stated above under names, a selector can have one of three forms.
Smalltalk variables can take any object type. No type declaration is needed, and in fact no type declaration is possible. Regardless of the current class of the value of an object, it can be assigned any other object in any other class at any time. Variables are created with the value nil. The differences among Smalltalk variables are in where they are defined, and how they are accessed, whether by objects within one class, shared among several classes, or accessible anywhere by anything.
{classname} bindingOf: #{variablename}
For example,
Preferences bindingOf: #Parameters
In addition to these regular objects defined within particular classes, there are pseudo-variables that have values depending on the class in which they are used, or act as global constants. The distinguishing characteristic of pseudo-variables is that they can be used anywhere, and their values cannot be changed by assignment.
A class definition has the form
SupercassName subclass: #Classname instanceVariableNames: 'var1 var2' classVariableNames: 'ClassVar1 ClassVar2' poolDictionaries: 'ClassDictionary' category: 'Category-Name'
A method definition has the form
MethodPattern "Method comment" | temporaryVariable | code. ^returnValue
Assignment
Any value can be assigned to any variable in the forms
var := value
var _ value
var ← value
Return value
An expression within a method body of the forms
^value
↑value
says to terminate execution of the method and return the value specified as the value of the method. If a method terminates without executing such an expression, the value returned is the receiver of the message that invoked the method.
Expression Sequences
Smalltalk expressions separated by period or dot characters are executed in sequence. For example,
x:=3. y:=4. z:=x+y
A final dot is optional.
Cascading
A sequence of messages can be sent to a single object by separating the methods with semicolons. The value returned by such as expression is the result of the last message sent. For example, constructing a list as an OrderedCollection in Smalltalk can be done in this manner.
aList := (OrderedCollection new) add: 100; add: 250 * 10; add: 'peter'; add: (Point x: 10 y: 20); yourself.
The message yourself instructs an object to return its current value, in contrast to the add: message, which returns the value added to the list.
Blocks
A class called BlockContext provides three extensions to Squeak syntax, for sequences of expressions with optional arguments and local variables.
[exp1. exp2. exp3]
When this block is sent the message value, it will execute the three expressions in sequence, and return the value of the last one. When value is sent to a block containing zero statements, that is
[] value
it returns nil.
[:arg1 :arg2|arg1+arg2]
The arguments can be used in any expression within the block. Invoke such a block using the value: selector for up to 4 arguments.
[:arg1 :arg2|arg1+arg2] value: 3 value: 4
b := [sum: index:||n: |sum := 0. index :=0. WhileTrue index<n[sum :=sum+index. index :=index+1]]
b value 5
15
Here b is created as a block-valued variable. In the next expression a sum is initialized to 0 and then the successive values of the index variable are added, from 1 to 5, resulting in 1+2+3+4+5 or 15.
Control Structures
Messages sent to Boolean or integer-valued objects allow the definition of a wide variety of control structures in Squeak, using the classes BlockContext, Number, Boolean, Object, ProtoObject, UndefinedObject, and subclasses of Collection. These are not part of the base Squeak syntax, but are defined as messages in the classes of the expected value types. For example, ifNil: is defined for nil, in the UndefinedObject class, as
ifNil: aBlock "A convenient test, in conjunction with Object ifNil:" ^ aBlock value
and for all other objects in the class ProtoObject with the body
^self
false ifTrue: [3] ifFalse: [2]
yields 2
nil ifNil: [3] ifNotNil: [2]
yields 3
gcd: anInteger | n m | n _ self. m _ anInteger. [n = 0] whileFalse: [n _ m \\ (m _ n)]. ^ m abs
The code above uses the Euclidean algorithm for greatest common divisor by taking remainders until a remainder of 0 is reached, that is, until one number divides the other.
[sum:||n m|sum =:0.n timesRepeat:[sum =: sum + m]]
yields m*n.
collection do:[x|x*x]
This squares each element in a collection, placing the results in a new collection of the same type.
These messages are sent to a number to specify a sequence of values to use as arguments to a block, with the resulting values placed in a list. Thus
10 to: 15 do: aBlock
calls for evaluating aBlock with arguments 10 11 12 13 14 15, and
1 to: 11 by: 2 do: aBlock
provides the values 1 3 5 7 9 11 as arguments to aBlock.
The receiver of caseOf: can be any object except instances of ProtoObject. The argument of caseOf: must be a BlockAssociationCollection, that is an instance of Dictionary in which each key is associated with a block. The receiver is looked up in the dictionary. If found, the associated block is executed. If not, an error results unless there is another block provided as the argument to otherwise:, in which case that block is executed.
Get further details from http://wiki.squeak.org/squeak/uploads/SqueakLanguageRef.3.html, and give examples.
Precedence
The order of precedence in Smalltalk expressions is as follows, from highest to lowest.
Expressions within parentheses, such as
3+(exp)
Unary expressions, such as
Class new
Binary expressions, such as
3+4
Keyword expressions, such as
array at: index put: value
When these rules are not determinative, parsing goes from left to right. There is no arithmetic precedence. For example,
3+2*4
is 11 in FORTRAN due to the higher precedence of multiplication, or in APL, which has no precedence but parses from right to left. In Smalltalk it is equivalent to
(3+2)*4
which evaluates to 20.
No attempt has been made here to explain essential structured Squeak object types such as lists, arrays, and dictionaries, or indeed any of the Squeak object types. Consult a Squeak tutorial or language reference for these and many other language details, or use the Squeak IDE tools described elsewhere in this manual to examine the definitions of Squeak objects and their interrelations directly.
There has been error in communication with Booktype server. Not sure right now where is the problem.
You should refresh this page.