|This page has links to websites or programs not trusted by Scratch or hosted by Wikipedia. Remember to stay safe while using the Internet, as we can't guarantee the safety of other websites.|
|This article or section documents something not included in the current version of Scratch (3.0). It is only useful from a historical perspective.|
Many Scratchers wanted to get into the Scratch browser and tinker with the source code, and a whole host of modifications sprang up as a result. These modifications sometimes allow users to edit Squeak code as part of their features, such as Panther, where users can create their own blocks using Squeak. With this sudden craze of modifying Scratch, a great many guides and questions have been posted all over the Advanced Topics teaching various aspects of editing Scratch and using Squeak. This Squeak "library" allows all the creators of these guides to pool their resources and compile a large collection of easy to understand tutorials in using Squeak to modify Scratch.
- 1 How a block comes to be
- 2 Expressions, objects, and messages
- 3 Types of objects
- 4 Classes and instances
- 5 Adding a block
- 6 Creating a class
- 7 Morphic classes
- 8 Smalltalk blocks
- 9 Errors
- 10 See Also
- 11 External Links
- 12 Notes
How a block comes to be
A block consists of two parts: the block specification and the method. The block spec tells Scratch how the block should appear and what it should do. It has four parts: the title, which contains the text of the block label along with its argument specifications; the block type, which is a symbol indicating what kind of block (stack, reporter, predicate, etc.) it should be; the message selector, which tells Scratch what code the block must run; and any default arguments. (An argument is a block input.) The method is the sequence of Smalltalk code the block runs.
- See also: Arguments#Scratch internals
In Scratch, an argument is added to a block spec title using a percent sign followed by a letter indicating the type of argument. For example, the block spec title of
move () steps is "move %n steps"; the "%n" indicates that the block should have a number argument. Here is a list of commonly used argument types, followed by the specification for Scratch and Panther and a description:[note 1]
|String||%s||$String$||Accepts any characters|
|Number||%n||$Number$||Accepts digits, decimal points, and the minus sign|
|Boolean||%b||$Boolean$||Accepts Boolean (diamond) blocks|
|Sprite||%m||$Sprite$||A dropdown with a list of sprites|
|Variable||%v||$Variable$||A dropdown with a list of variables|
|Attributes||%a||$Attributes$||A dropdown with a list of attributes (direction etc.)|
|Color picker||%C||$Color$||A color picker with a popout pallet|
|Color picker||%c||$ScreenColor$||A color picker without a popout pallet|
|Directions||%d||$Directions$||A dropdown with a list of directions|
|Drums||%D||$Drums$||A dropdown with a list of drum sounds|
|Events||%e||$Event$||A dropdown with a list of broadcasts|
|Math functions||%f||$MathFunctions$||A dropdown with a list of math functions (abs, sin etc.)|
|Effects||%g||$Effects$||A dropdown list of effects such as color and brightness|
|Sensors||%h||$SensorNames$||A dropdown list of sensor names such as slider (for a PicoBoard)|
|Sensor booleans||%H||$SensorBooleans$||A dropdown list of PicoBoard booleans such as "A connected?"|
|Instruments||%I||$Instruments$||A dropdown list of instruments|
|List options||%i||$ListIndex$||A dropdown of list indexes (1, last, any)|
|Key options||%K||$Keys$||A dropdown list of keyboard keys|
|Lists||%L||$List$||A dropdown list of lists|
|Costumes||%l||$Costumes$||A dropdown list of costumes|
|Motors||%W||$MotorNames$||A dropdown list for the Motor Blocks|
|Notes||%N||$Notes$||A note space with popout keyboard|
|Sounds||%S||$SoundNames$||A dropdown list of sounds|
These are the block types:
|Color (Panther only)||g|
|Timed||t||These blocks do something over a given period of time. For example: Wait () Secs, Play Note () for () Beats|
|Special form||s||A special form is any block does not behave as ordinary blocks do. For example, Wait Until () must repeatedly run its argument to find out whether or not it should stop; if it were an ordinary block, its argument would only be ran once.|
Each hat block has its own block type symbol, not listed here.
Expressions, objects, and messages
To begin with Squeak, shift-click the R in the Scratch logo and select "turn fill screen off". (You could also download the Scratch source code, which makes this step unnecessary and is easier to understand.) Smalltalk code consists mostly of expressions. Each expression can be evaluated to produce a result called a value. The simplest kind of expression is called a literal expression; numerals and single-quoted strings are both literal expressions. For example,
42 is an expression whose value is the number 42.
Smalltalk is an object-oriented programming language. Every value in Smalltalk is an object; objects include numbers, strings, lists, blocks, the stage, and sprites. In OOP, rather than having a set of blocks to operate on data of each type (numbers and strings are two examples of types), the behavior is part of the data itself. For example, the expression
((3) * (4)) in Scratch applies
(() * ()) to two arguments, both of which are numbers, and reports their product; but
3 * 4 in Smalltalk, on the other hand, sends a message to 3, the receiver, with two parts: the message selector, "*", and an argument, 4. (The receiver and argument expressions may be expressions of any kind.)
A workspace is a window that may be used to evaluate expressions. To open a workspace, click in the grey space that appears around Scratch to open the world menu, select "open…", and select "workspace". Then hover the mouse-pointer over the workspace, type an expression, right-click (if you are using Microsoft Windows) or hold down Control and click (otherwise) on the workspace to bring up a context menu, and select "print it".
Smalltalk, like Scratch, uses keyword arguments, which means the message selector is written combined with the argument expressions. (There are two exceptions to this: messages with no arguments and a few infix message selectors, like "+" and "*".) Each part of the message selector is followed by a colon. For example, the message selector of
go to x: (0) y: (0) is "gotoX:y:". An argument expression should follow each colon, so it could be used as follows:
aSprite gotoX: 0 y: 0
|Note:||In this tutorial, the format multipleWordsWithoutSpaces is used a lot. This is standard Smalltalk practice to write many words without spaces, and is called camel case.|
In Smalltalk, a comment is enclosed in double quotation marks ("). Comments are not evaluated, but can be used to explain what is happening.
Types of objects
A string is an object that represents some text. In Smalltalk, string literal expressions are written within single quotes, for example:
'hello'. To put a single quote in a string, use two single quotes in a row:
'it''s fine'. Strings are joined with a comma message:
'Hello ', 'world' "Hello world"
A symbol is a special kind of string used in Smalltalk: both message selectors and block types are symbols. They are usually written without spaces. Symbol literal expressions begin with a #, for example:
An array is a finite sequence of objects, like a list in Scratch. However, Scratch lists must be named using the "Make a list" button, whereas in Smalltalk an array is an object like any other and may be stored in a variable or even another array. (Arrays are said to be first class in Smalltalk.)
Array literal expressions are written like this:
#(item1 item2 ...). Each item may be a number, string, symbol (as in this case), or another array; symbols and arrays written inside an array literal expression need not be preceded by #.
An item of an array is accessed using an at: message. For example:
#(entree main dessert) at: 1 "entree"
A block spec is an array. For example, the block spec for
move () steps is written as:
('move %n steps' - forward:)
Here, "move %n steps" is the title, - is the block type, and "forward:" is the message selector.
Classes and instances
In Smalltalk, types are represented by objects called classes: each object is an instance of a particular class. A class has a name; a set of instance variables, which are variables local to each instance of the class; and a set of instance methods, which define the behavior of its instances. For example, 3 is an instance of the class SmallInteger; when 3 receives the * 4 message, it finds the corresponding instance method in SmallInteger, which answers with the product, 12.
Classes may also have class methods, which are used when a message is sent to the class itself.
A system browser is a window used to edit classes and their methods. To open the system browser, open the world menu and select "open…" followed by "browser".
When an object is assigned to a variable, a copy of it is not created. The variable only stores a new pointer to the object, which may be used to send the object messages. For example, if the variable cat points to a sprite which is then assigned to aSprite, cat and aSprite both point to the same object, so if cat is rotated, aSprite will answer the new direction. Thus, classes should implement a copying protocol, a message whose method reports a copy of the object by actually assembling the copy attribute by attribute. A copying protocol example will be given in a following section.
Every class but one, Object, inherits from another. An inheriting class, called a subclass, is given all the variables and methods of the parent class. For example, the stage and sprites have many things in common: both have scripts, variables, lists, graphic effects, and sounds. The stage is an instance of ScratchStageMorph and sprites are instances of ScratchSpriteMorph. Both of these classes are subclasses of ScriptableScratchMorph, which defines the behavior common to both the stage and sprites: adding scripts, variables, lists, and sounds, playing sounds, broadcasting, changing appearance, and so on. (Morphic is the user interface system used by Scratch. Morphs are the basic graphical objects displayed on the screen; blocks, lists, the stage, and sprites are all morphs. Morphic class inherit from the class Morph, which itself inherits from Object; this is an inheritance hierarchy.)
Adding a block
To evaluate an ordinary block, Scratch sends a message to the stage or sprite. Suppose you want to add
(distance to x: () y: () :: sensing) to Scratch. For this to work sprites should be able to understand
distanceToX:y:, so a method should be added to ScratchSpriteMorph. The system browser has four columns along the top and a large space below. In the leftmost column, which lists categories of classes, select "Scratch-Objects". Then in the next column, which lists classes, select "ScratchSpriteMorph". In second column from the right, which lists message categories, select "sensing ops". Upon selecting a category some highlighted text will appear below; this is the template for a method definition:
message selector and argument names "comment stating purpose of message" | temporary variable names | statements
The message selector and argument names tell Squeak what message this method is for and what variable names should be given to each argument. This is followed by a comment, which you could add if the purpose of the message is not quite clear; the names of temporary variables used by the method, which can be omitted; and a sequence of statements, which is for the most part a sequence of expressions seperated by full stops, but the final statement may begin with a "^" followed by an expression whose value the method should report.
To find its x and y coordinates, the sprite can send itself
self is a special variable in Smalltalk which is used for this. The distance between a sprite and a point is found by using the Pythagorean theorem. Hover the mouse-pointer over the text to edit it and enter:
distanceToX: x y: y ^ ((self xpos - x) squared + (self ypos - y) squared) sqrt
Then right-click (on Microsoft Windows) or Control-click (otherwise), select "accept", and type your initials if prompted.
Now sprites can understand
distanceToX:y:, so all that is left to do is to add a block spec. The title should be "distance to x:%n y:%n", the block type should be r, and the message selector should be "distanceToX:y:". The class method for
blockSpecs reports an array of block specs following category names. Class methods are found by clicking "class", below the list of classes. Do so, select the category block specs and the message
blockSpecs, scroll until you find the Sensing blocks, and above or below
(distance to [ v]) place the block spec:
('distance to x:%n y:%n' r distanceToX:y:)
(If you have the Scratch source code, you may like to press Tab to align your block spec with the others.) Right-click or Control-click and select "accept", and then as soon as you select Sensing the new block will appear and can be used like any other.
A temporary variable is a variable used only by the method while it is being evaluated. Temporary variables are listed below the message selector between two pipes (|). They are restricted to letters and digits, and cannot be reserved (i.e., "self").
If the Scratch source code is not present, you will see many names like "t1", "t2", etc., but this is not necessary; it is almost always better to give variables self-descriptive names.
A variable, temporary or otherwise, is set using the syntax
variable _ value. (The new value is said to be assigned to the variable.) For example:
modifyAVariable | aVar | aVar _ 10
|Note:||In the Squeak editor, the underscore is depicted as an arrow pointing left (←).|
Creating a class
Hover the mouse-pointer over the leftmost column of the system browser. A scrollbar will appear; click the button with the dash (–) on it. Then select "add item…". When prompted, type in the name of the category to which your class belongs. A category can have many classes, like vehicles can have car and helicopter. For this tutorial, name it "Vehicles".
In the editing pane, you should have this code:
Object subclass: #NameOfClass instanceVariableNames: 'instVarName1 instVarName2' classVariableNames: 'ClassVarName1 ClassVarName2' poolDictionaries: '' category: 'Vehicles'
Replace it with this. Read the annotations carefully.
Object subclass: #Car "Class name" instanceVariableNames: 'driver color' classVariableNames: '' "ignore for now" poolDictionaries: '' "ignore for now" category: 'Vehicles'
Now right-click or Control-click on the pane and select "accept". You have made a class! The class is named "Car", its instance variables are
color, and it is in the category Vehicles.
Next, we will add a simple method. Click on "Car" in the list second from the left in the System Browser. In the next list, click "-- all --", and enter the following:
drive Transcript show: 'Vroom!'
Again, right-click or Control-click and select "accept". Instances are created by sending the class a
new message. Now open the world menu, select "open…", and select "transcript". The transcript is a window where Squeak programs can log values for debugging purposes. Also open a workspace, and enter the following:
myFamilyCar _ Car new. myFamilyCar drive.
Right-click or Control-click the workspace and select "do it". In the transcript, you should see the text "Vroom!"
To be able to find or decide the color or driver of a car, it is necessary to write accessor methods and mutator methods. For example:
color ^ color driver ^ driver color: aColor color _ aColor driver: aDriver driver _ aDriver
These can be used like this:
myFamilyCar color: 'black'. myFamilyCar driver: 'Dad'. myFamilyCar color.
A method to copy cars can be written as follows:
copy | myCopy | myCopy _ Car new. myCopy color: self color. myCopy driver: self driver. ^ myCopy
Now to copy a car, you can just say:
anotherFamilyCar _ myFamilyCar copy
To create a Morphic class, make a subclass of Morph. For example:
Morph subclass: #MyMorph instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'My-Morphs'
This morph can already be drawn, with the following code (in a workspace):
MyMorph new openInWorld
A blank blue rectangle will appear. A more interesting morph can be created by implementing
drawOn: aCanvas "Draw a randomly colored oval." | aColor | aColor _ Color random. aCanvas fillOval: self bounds color: aColor
Morphs can react to events, such as clicks. Two methods are required: one to listen for clicks and one to act on the event:
handlesMouseDown: evt ^ true "Listen." mouseDown: evt self position: self position + (0@10)
Morphs can also be animated. Here, three methods are required:
startAnimation "Initialization." self startStepping stepTime "Answer the period in milliseconds." ^ 75 step "Move slightly left and downwards." self position: self position + (1@1)
Of course, to use a morph effectively, it must be assigned to a variable, or it will not be editable. For example:
aMorph _ MyMorph new openInWorld
A block (not to be confused with a Scratch block) is similar to a C shape in Scratch — it may or may not be evaluated, or may be run many times. It is just code which the program can do anything with. Blocks are written like normal code, but in square brackets. For example,
square of width () :: pen could be written as follows:
square: width self putPenDown. 4 timesRepeat: [ self forward: width. self turnRight: 90. "The stage must be asked to make the line appear:" (self ownerThatIsA: ScratchStageMorph) updateTrailsForm]. self putPenUp
Here, 4 is sent a
timesRepeat: message with a block as an argument, which it evaluates four times. The Smalltalk messages
ifTrue:, etc. not special: any message could have a block as an argument.
When an error occurs in a script, if you are not in fill screen mode, or have turned error catching off, Squeak displays popups instead of the block turning red. These error messages appear to help you figure out what the problem is:
In the system browser, syntax errors can not be accepted:
- All About Squeak Smalltalk by Pecola1
- Bank Account Tutorial by John Maloney
- Reading Smalltalk, a guide for C++/Java programmers
- In Panther, an argument is added to a block title by writing the name of the argument type between dollar signs. This allows any number of argument types to be created, whereas in Scratch only 26×2 = 52 types of arguments can be made.
- All C blocks are also special forms, though they do not use s.