FLOSS Manuals

 English |  Español |  Français |  Italiano |  Português |  Русский |  Shqip

Etoys Reference Manual Vol. II

Squeak: The Irreducible Minimum

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.

Squeak Structure

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.

Objects

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)

  • a set of selectors specifying operations on instances of the object
  • a set of protocols, each of which is usually a set of selectors related in some way
  • a set of instance methods containing code to implement the selectors
  • sets of variables of various kinds

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.

Classes, Subclasses, Superclasses, and Metaclasses

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.

Categories and Protocols

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.

Names

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.

  • Names of classes are global.
  • Instance variables are private, accessible only by methods in the class of their instance.
  • Pool variables are shared among classes that declare them.
  • Selectors are accessible anywhere, but their definitions are private, and their names begin with lowercase letters.
  • There are also binary selectors made of one or two non-alphanumeric characters, such as + and <=. 

Literal Constants

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.

  • numbers of various types, including integers in a variety of bases, floating point numbers in decimal or scientific notation, rational numbers, and complex numbers.
  • characters, in the form $a for ASCII or MacRoman, or as Unicode characters.
char:=Character value: 16r0411
wideString := String with: char.  

This prints as Russian Cyrillic 'Б'.

  • strings entered with surrounding quote marks, such as "Hello"
  • symbols entered with a leading # and an alphanumeric name
  • arrays of other literals in the form #(3 1 2) for an array of three integers

    Instances

    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.

    Messages, Selectors, and Methods

    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.

    • An ASCII alphanumeric name, starting with a lowercase letter. In this case, the selector specifies a message to a single object, called its receiver. Example: new.
    • A non-alphanumeric name of one or two characters, which represents a binary operation on the receiver and another object. Example: +.
    • A composite name consisting of two or more ASCII alphanumeric parts, each beginning with a lowercase letter and ending with a colon ':'. This sends a message to the receiver with an argument for each part. Example: at:put:.
    Method specifications consist of the message pattern, optional temporary variable declarations, and code to execute.

    Variable Types

    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.

    • Instance variables are defined in a class definition, and are created at the same time as the instance. Each instance has its own set, and cannot directly access those of another instance.
    • Class variables, that is instance variables of the metaclass of this class, are defined in the class definition, and created at the same time as the class. They can be accessed by the class, and by any instance of the class, at any time, using the syntax
    {classname} bindingOf: #{variablename}
    

    For example,

    Preferences bindingOf: #Parameters
    
    • Temporary variables are declared within an instance method. They are created at the beginning of execution of the method, with value nil, and can be used freely within the method body, but nowhere else. They disappear when the method completes.
    • Argument names are specified in message patterns, and given values when the message is sent. Their values cannot be changed by assignment.
    • Pool variables are declared within one or more classes, and created at the time of the first definition. Their values are accessible within each class that declares them.
    • Global variables are accessible anywhere. They are managed in a SystemDictionary called Smalltalk with more than 2000 entries.

    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.

    • self refers to the receiver of the current message. Sending a message to self says to use the version of the method named that the class of the receiver specifies, or one found further up its superclass chain. It is important to understand that self does not refer to the class in which the method containing it is defined, in the case where that method is applied to an instance of a subclass.
    • super within a method refers to the receiver of the current message. Sending a message to super says to use a version of the method named found not in the class of the receiver, but in its superclass chain. This allows the method defined for the receiver to access the method defined for its superclass, which would otherwise be hidden from it. It is important to understand that super does not refer to the class in which the method containing it is defined, in the case where that method is applied to an instance of a subclass. This can be one of the most confusing aspects of Smalltalk and Squeak.
    • nil is the value given to freshly-created values. Its normal interpretation is that the variable has no value. It should normally not be used as an extra value on a par with others, to avoid confusion with variables that have not been given any other value after their creation.
    • true is a special value for Boolean variables. It is the sole instance of the class True.
    • false is a special value for Boolean variables. It is the sole instance of the class False.

    Smalltalk Syntax

    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.

    • Sequence:
    [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.

    • With arguments:
    [: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

      In this case, sending the message value: 3 results in a block with one argument, and providing the second argument value results in execution of the block and returning the value that results.
      • With arguments and local variables:
      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
        
        • ifTrue:
        • ifFalse:
        false ifTrue: [3] ifFalse: [2]
        

        yields 2

        • ifNil:
        • ifNotNil: 
        nil ifNil: [3] ifNotNil: [2]
        

        yields 3

        • whileTrue:
        • whileFalse:
        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.

          • timesRepeat:
          [sum:||n m|sum =:0.n timesRepeat:[sum =: sum + m]]
          

            yields m*n.

            • do: 
            collection do:[x|x*x]

            This squares each element in a collection, placing the results in a new collection of the same type.

            • to: do:
            • to: by: do: 

            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.

            • caseOf: [otherwise:] 

            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.

              These define a message to be sent to a block asking for a Boolean result, or to an object asking whether it is nil (class UndefinedObject) or an object of any other class. Getting a non-Boolean answer results in an error. Depending on the result of the block, a second alternative block may be executed, or a choice made between two alternative blocks in the combinations IfTrue: IfFalse: and IfNil: IfNotNil:. Some blocks ask the test block to run once, and then run an alternative block zero or one time depending on the result. Some execute the test block until a specific value results, and run an alternative block each time until that result occurs. Do: repeats the alternative block once for each value of a collection, and collects the results into a similar structure. The CaseOf: constructs choose a block from a BlockAssociationCollection associated with the class of the receiver, which can be any kind of Object.
              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.

              Further Documentation

              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.