In this chapter, we will develop a simple game: LightsOut (http://en.wikipedia.org/wiki/Lights_Out_(game)). Along the way we will show most of the tools that Pharo programmers use to construct and debug their programs, and show how programs are shared with other developers. We will see the browser, the object inspector, the debugger and the Monticello package browser.
In Pharo you can develop in a traditional way, by defining a class, then its instance variables, then its methods. However, in Pharo your development flow can be much more productive than that! You can define instance variables and methods on the fly. You can also code in the debugger using the exact context of currently executed objects. This chapter will sketch such alternate way and show you how you can be really productive.
To show you how to use Pharo's programming tools, we will build a simple game called Lights Out. The game board consists of a rectangular array of light yellow cells. When you click on one of the cells, the four surrounding cells turn blue. Click again, and they toggle back to light yellow. The object of the game is to turn blue as many cells as possible.
Lights Out is made up of two kinds of objects: the game board itself, and 100 individual cell objects. The Pharo code to implement the game will contain two classes: one for the game and one for the cells. We will now show you how to define these classes using the Pharo programming tools.
We have already seen the browser in Chapter 0.8 : A Quick Tour of Pharo where we learned how to navigate to packages, classes and methods, and saw how to define new methods. Now we will see how to create packages and classes.
World menu, open a System Browser. Right-click on an existing
package in the Package pane and select
Add package... from the menu. Type
the name of the new package (we use
PBE-LightsOut) in the dialog box and
OK (or just press the return key). The new package is created, and
positioned alphabetically in the list of packages (see Figure
Hints: You can type
PBE in the filter to get your package filtered out
the other ones (See Figure 0.21).
At this point there are, of course, no classes in the new package. However, the main editing pane displays a template to make it easy to create a new class (see Figure 0.21).
This template shows us a Pharo expression that sends a message to a class
Object, asking it to create a subclass called
new class has no variables, and should belong to the category (package)
We simply edit the template to create the class that we really want. Modify the class creation template as follows:
mouseActionto the list of instance variables.
You should get the following class definition:
This new definition consists of a Pharo expression that sends a message to
the existing class
SimpleSwitchMorph, asking it to create a subclass called
LOCell. (Actually, since
LOCell does not exist yet, we passed the symbol
#LOCell as an argument, representing the name of the class to create.) We
also tell it that instances of the new class should have a
instance variable, which we will use to define what action the cell should take
if the mouse should click on it.
At this point you still have not created anything. Note that the top right of
the panel changed to orange. This means that there are unsaved changes. To
actually send this subclass message, you must save (accept) the source code.
Either right-click and select
Accept, or use the shortcut
"Save"). The message will be sent to
SimpleSwitchMorph, which will cause the
new class to be compiled. You should get the situation depicted in Figure
Once the class definition is accepted, the class is created and appears in the class pane of the browser (see Figure 0.22). The editing pane now shows the class definition. Below you get the Quality Assistant's feedback: It runs automatically quality rules on your code and reports them.
Pharoers put a very high value on the readability of their code, but also good quality comments.
People have the tendency to believe that it is not necessary to comment well written methods: it is plain wrong and encourages sloppiness. Of course, bad code should renamed and refactored. Obviously commenting trivial methods makes no sense. A comment should not be the code written in english but an explanation of what the method is doing, its context, or the rationale behind its implementation. When reading a comment, the reader should be comforted that his hypotheses are correct.
For the class comment, the Pharo class comment template gives a good idea of a strong class comment. Read it! It is based on CRC for Class Responsibility Collaborators. So in a nutshell the comments state the responsibility of the class in a couple of sentences and how it collaborates with other classes to achieve this responsibilities. In addition we can state the API (main messages an object understands), give an example (usually in Pharo we define examples as class methods), and some details about internal representation or implementation rationale.
Select the comment button and define a class comment following this template
Historically, Pharo packages were implemented as "categories" (a group of classes). With the newer versions of Pharo, the term category is being deprecated, and replaced exclusively by package.
If you use an older version of Pharo or an old tutorial, the class template will be as follow:
It is equivalent to the one we mentioned earlier. In this book we only use the term package. The Pharo package is also what you will be using to version your source code using the Monticello versioning tool.
Now let's add some methods to our class. Select the protocol
in the protocol pane. You will see a template for method creation in the editing
pane. Select the template text, and replace it by the following (do not forget
to compile it):
Note that the characters
'' on line 3 are two separate single quotes with
nothing between them, not a double quote!
'' denotes the empty string.
Another way to create an empty string is
String new. Do not forget to
accept this method definition.
Notice that the method is called
initialize. The name is very significant!
By convention, if a class defines a method named
initialize, it is
called right after the object is created. So, when we execute
initialize is sent automatically to this newly created object.
initialize methods are used to set up the state of objects, typically to set
their instance variables; this is exactly what we are doing here.
The first thing that this method does (line 2) is to execute the
method of its superclass,
SimpleSwitchMorph. The idea here is that any
inherited state will be properly initialized by the
initialize method of the
superclass. It is always a good idea to initialize inherited state by sending
super initialize before doing anything else. We don't know exactly what
initialize method will do (and we don't care), but
it's a fair bet that it will set up some instance variables to hold reasonable
default values. So we had better call it, or we risk starting in an unclean
The rest of the method sets up the state of this object. Sending
'', for example, sets the label of this object to the empty string.
0@0 corner: 16@16 probably needs some explanation.
Point object with
y coordinates both set to 0. In
0@0 sends the message
@ to the number 0 with argument 0. The
effect will be that the number 0 will ask the
Point class to create a new
instance with coordinates
(0,0). Now we send this newly created point the
corner: 16@16, which causes it to create a
16@16. This newly created rectangle will be assigned
bounds variable, inherited from the superclass.
Note that the origin of the Pharo screen is the top left, and the
coordinate increases downwards.
The rest of the method should be self-explanatory. Part of the art of writing good Pharo code is to pick good method names so that the code can be read like a kind of pidgin English. You should be able to imagine the object talking to itself and saying "Self, use square corners!", "Self, turn off!".
Notice that there is a little green arrow next to your method (see Figure 0.23). This means the method exists in the superclass and is overridden in your class.
You can immediately test the effect of the code you have written by creating a
LOCell object and inspecting it: Open a
Playground, type the
LOCell new, and Inspect it (using the menu item with the same
The left-hand column of the inspector shows a list of instance variables and the value of the instance variable is shown in the right column (see Figure 0.24).
If you click on an instance variable the inspector will open a new pane with the detail of the instance variable (see Figure 0.25).
The bottom pane of the inspector is a mini-playground. It's useful because in
this playground the pseudo-variable
self is bound to the object selected.
Go to that Playground at the bottom of the pane and type the text
(200@200 corner: 250@250) Do it. To refresh the values, click on the
update button (the blue little circle) at the top right of the pane. The
bounds variable should change in the inspector. Now type the text
openInWorld in the mini-playground and Do it.
The cell should appear near the top left-hand corner of the screen (as shown in
Figure 0.26) and exactly where its bounds say that it should
appear. Meta-click on the cell to bring up the Morphic halo. Move the cell with
the brown (next to top-right) handle and resize it with the yellow
(bottom-right) handle. Notice how the bounds reported by the inspector also
change. (You may have to click refresh to see the new bounds value.) Delete the
cell by clicking on the
x in the pink handle.
Now let's create the other class that we need for the game, which we will name
Make the class definition template visible in the browser main window. Do this
by clicking on the package name (or right-clicking on the Class pane and
Add Class). Edit the code so that it reads as follows, and
Here we subclass
Morph is the superclass of all of the
graphical shapes in Pharo, and (unsurprisingly) a
BorderedMorph is a
Morph with a border. We could also insert the names of the instance
variables between the quotes on the second line, but for now, let's just leave
that list empty.
Now let's define an
initialize method for
LOGame. Type the following
into the browser as a method for
LOGame and try to Accept it.
Pharo will complain that it doesn't know the meaning of
cells (see Figure
0.27). It will offer you a number of ways to fix this.
Choose Declare new instance variable, because we want
cells to be an
At this stage if you open a
LOGame new, and Do it,
Pharo will complain that it doesn't know the meaning of some of the terms (see
Figure 0.28). It will tell you that it doesn't know of
cellsPerSide, and will open a debugger. But
not a mistake; it is just a method that we haven't yet defined. We will do so,
Now let us do it: type
LOGame new and Do it. Do not close the debugger.
Click on the button
Create of the debugger, when prompted, select
LOGame, the class which will contain the method, click on ok, then when
prompted for a method protocol enter
accessing. The debugger will create the
cellsPerSide on the fly and invoke it immediately. As there is no
magic, the created method will simply raise an exception and the debugger will
stop again (as shown in Figure 0.29) giving you the
opportunity to define the behavior of the method.
Here you can write your method. This method could hardly be simpler: it answers the constant 10. One advantage of representing constants as methods is that if the program evolves so that the constant then depends on some other features, the method can be changed to calculate this value.
Define the method
cellsPerSide in the debugger. Do not forget to compile the
method definition by using Accept. You should obtain a situation as shown by
Figure 0.30. If you press the button Proceed the
program will continue its execution - here it will stop since we did not define
newCellAt:. We could use the same process but for now we stop to
explain a bit what we did so far. Close the debugger, and look at the class
definition once again (which you can do by clicking on LOGame on the second
pane of the System Browser), you will see that the browser has modified it
to include the instance variable
Let us now study the method
At line 2, the expression
| sampleCell width height n | declares 4
temporary variables. They are called temporary variables because their scope and
lifetime are limited to this method. Temporary variables with explanatory names
are helpful in making code more readable. Lines 4-7 set the value of these
How big should our game board be? Big enough to hold some integral number of
cells, and big enough to draw a border around them. How many cells is the right
number? 5? 10? 100? We don't know yet, and if we did, we would probably change
our minds later. So we delegate the responsibility for knowing that number to
another method, which we name
cellsPerSide, and which we will write in a
minute or two. Don't be put off by this: it is actually good practice to code by
referring to other methods that we haven't yet defined. Why? Well, it wasn't
until we started writing the
initialize method that we realized that we
needed it. And at that point, we can give it a meaningful name, and move on,
without interrupting our flow.
The fourth line uses this method,
n := self cellsPerSide. sends the message
self, i.e., to this very object. The response, which
will be the number of cells per side of the game board, is assigned to
The next three lines create a new
LOCell object, and assign its width and
height to the appropriate temporary variables.
Line 8 sets the bounds of the new object. Without worrying too much about the details just yet, believe us that the expression in parentheses creates a square with its origin (i.e., its top-left corner) at the point (5,5) and its bottom-right corner far enough away to allow space for the right number of cells.
The last line sets the
LOGame object's instance variable
cells to a
Matrix with the right number of rows and columns. We do this
by sending the message
new: tabulate: to the
Matrix class (classes are
objects too, so we can send them messages). We know that
takes two arguments because it has two colons (:) in its name. The arguments go
right after the colons. If you are used to languages that put all of the
arguments together inside parentheses, this may seem weird at first. Don't
panic, it's only syntax! It turns out to be a very good syntax because the name
of the method can be used to explain the roles of the arguments. For example, it
is pretty clear that
Matrix rows: 5 columns: 2 has 5 rows and 2 columns, and
not 2 rows and 5 columns.
Matrix new: n tabulate: [ :i :j | self newCellAt: i at: j ] creates a new
n X n matrix and initializes its elements. The initial value of each element
will depend on its coordinates. The (i,j)th element will be initialized to
the result of evaluating
self newCellAt: i at: j.
Before we define any more methods, let's take a quick look at the third pane at the top of the browser. In the same way that the first pane of the browser lets us categorize classes into packages, the protocol pane lets us categorize methods so that we are not overwhelmed by a very long list of method names in the method pane. These groups of methods are called "protocols".
The browser also offers us the
--all-- virtual protocol, which, you will
not be surprised to learn, contains all of the methods in the class.
If you have followed along with this example, the protocol pane may well contain
the protocol as yet unclassified. Right-click in the protocol pane and
select categorize all uncategorized to fix this, and move the
method to a new protocol called initialization.
How does the System Browser know that this is the right protocol? Well, in
general Pharo can't know exactly, but in this case there is also an
initialize method in the superclass, and it assumes that our
method should go in the same protocol as the one that it overrides.
Pharoers frequently use the notation
Class >> method to identify the class
to which a method belongs. For example, the
cellsPerSide method in class
LOGame would be referred to as
LOGame >> cellsPerSide. Just keep in mind
that this is not Pharo syntax exactly, but merely a convenient notation to
indicate "the instance method
cellsPerSide which belongs to the class
LOGame". (Incidentally, the corresponding notation for a class-side method
LOGame class >> someClassSideMethod.)
From now on, when we show a method in this book, we will write the name of the
method in this form. Of course, when you actually type the code into the
browser, you don't have to type the class name or the
>>; instead, you just
make sure that the appropriate class is selected in the class pane.
Now let's define the other method that are used by
LOGame >> initialize.
LOGame >> newCellAt: at: in the
As you can see there are some tabulation and empty lines. In order to keep the
same convention you can right-click on the method edit area and click on
Format (or use
CMD-Shift-f shortcut). This will format your method.
The method defined above created a new
LOCell, initialized to position (i,
j) in the Matrix of cells. The last line defines the new cell's
to be the block
[ self toggleNeighboursOfCellAt: i at: j ]. In effect, this
defines the callback behaviour to perform when the mouse is clicked. The
corresponding method also needs to be defined.
toggleNeighboursOfCellAt:at: toggles the state of the four cells
to the north, south, west and east of cell (i, j). The only complication is that
the board is finite, so we have to make sure that a neighboring cell exists
before we toggle its state.
Place this method in a new protocol called
game logic. (Right-click in the
protocol pane to add a new protocol.) To move (re-classify) the method, you can
simply click on its name and drag it to the newly-created protocol (see Figure
To complete the Lights Out game, we need to define two more methods in class
LOCell this time to handle mouse events.
The method above does nothing more than set the cell's
to the argument, and then answers the new value. Any method that changes the
value of an instance variable in this way is called a setter method; a
method that answers the current value of an instance variable is called a
If you are used to getters and setters in other programming languages, you might
expect these methods to be called
Pharo convention is different. A getter always has the same name as the variable
it gets, and a setter is named similarly, but with a trailing ":", hence
mouseAction:. Collectively, setters and getters are
called accessor methods, and by convention they should be placed in the
accessing protocol. In Pharo, all instance variables are private to the
object that owns them, so the only way for another object to read or write those
variables is through accessor methods like this one. In fact, the instance
variables can be accessed in subclasses too.
Go to the class
LOCell >> mouseAction: and put it in the
Finally, we need to define a method
mouseUp:. This will be called
automatically by the GUI framework if the mouse button is released while the
cursor is over this cell on the screen. Add the method
LOCell >> mouseUp:
and then Categorize automatically the methods.
What this method does is to send the message
value to the object stored in
the instance variable
LOGame >> newCellAt: i at: j we
created the block
[self toggleNeighboursOfCellAt: i at: j ] which is
toggling all the neighbours of a cell and we assigned this block to the
mouseAction of the cell. Therefore sending the
value message causes this
block to be evaluated, and consequently the state of the cells will toggle.
That's it: the Lights Out game is complete! If you have followed all of the
steps, you should be able to play the game, consisting of just 2 classes and 7
methods. In a Playground, type
LOGame new openInWorld and Do it .
The game will open, and you should be able to click on the cells and see how it works. Well, so much for theory... When you click on a cell, a debugger will appear. In the upper part of the debugger window you can see the execution stack, showing all the active methods. Selecting any one of them will show, in the middle pane, the Smalltalk code being executed in that method, with the part that triggered the error highlighted.
Click on the line labeled
LOGame >> toggleNeighboursOfCellAt: at: (near the
top). The debugger will show you the execution context within this method where
the error occurred (see Figure 0.32).
At the bottom of the debugger is a variable zone. You can inspect the object that is the receiver of the message that caused the selected method to execute, so you can look here to see the values of the instance variables. You can also see the values of the method arguments.
Using the debugger, you can execute code step by step, inspect objects in parameters and local variables, evaluate code just as you can in a playground, and, most surprisingly to those used to other debuggers, change the code while it is being debugged! Some Pharoers program in the debugger almost all the time, rather than in the browser. The advantage of this is that you see the method that you are writing as it will be executed, with real parameters in the actual execution context.
In this case we can see in the first line of the top panel that the
toggleState message has been sent to an instance of
LOGame, while it
should clearly have been an instance of
LOCell. The problem is most likely
with the initialization of the cells matrix. Browsing the code of
LOGame >> initialize shows that
cells is filled with the return values
newCellAt: at:, but when we look at that method, we see that there is no
return statement there! By default, a method returns
self, which in the case
newCellAt: at: is indeed an instance of
LOGame. The syntax to return
a value from a method in Pharo is
Close the debugger window. Add the expression
^ c to the end of the method
LOGame >> newCellAt:at: so that it returns
Often, you can fix the code directly in the debugger window and click
Proceed to continue running the application. In our case, because the bug
was in the initialization of an object, rather than in the method that failed,
the easiest thing to do is to close the debugger window, destroy the running
instance of the game (with the halo
CMD-Alt-Shift and click), and create a
LOGame new openInWorld again because if you use the old game
instance it will still contain the block with the old logic.
Now the game should work properly... or nearly so. If we happen to move the
mouse between clicking and releasing, then the cell the mouse is over will also
be toggled. This turns out to be behavior that we inherit from
SimpleSwitchMorph. We can fix this simply by overriding
mouseMove: to do
Finally we are done!
By default when an error occurs in Pharo, the system displays a debugger. However, we can fully control this behavior. For example we can write the error in a file. We can even serialize the execution stack in a file, zip and reopen it in another image. Now when we are in development mode the debugger is available to let us go as fast as possible. In production system, developers often control the debugger to hide their mistakes from their clients.
Now that you have Lights Out working, you probably want to save it somewhere so that you can archive it and share it with your friends. Of course, you can save your whole Pharo image, and show off your first program by running it, but your friends probably have their own code in their images, and don't want to give that up to use your image. What you need is a way of getting source code out of your Pharo image so that other programmers can bring it into theirs.
We'll be discussing the various ways to save and share code in a future chapter, Chapter 0.66 : Sharing Code and Source Control. For now, here is an overview of some of the available methods.
The simplest way of doing this is by "filing out" the code. The right-click
menu in the Package pane will give you the option to
File Out the whole of
PBE-LightsOut. The resulting file is more or less human readable,
but is really intended for computers, not humans. You can email this file to
your friends, and they can file it into their own Pharo images using the file
Right-click on the
PBE-LightsOut package and file out the contents (see
Figure 0.33). You should now find a file named
the same folder on disk where your image is saved. Have a look at this file with
a text editor.
Open a fresh Pharo image and use the
File Browser tool (
Tools --> File
Browser) to file in the
PBE-LightsOut.st fileout (see Figure
fileIn. Verify that the game now works in the new
Although fileouts are a convenient way of making a snapshot of the code you have
written, they are definitevely "old school". Just as most open-source projects
find it much more convenient to maintain their code in a repository using SVN or
Git, so Pharo programmers find it more convenient to manage their code using
Monticello packages. These packages are represented as files with names ending
.mcz. They are actually zip-compressed bundles that contain the complete
code of your package.
Using the Monticello package browser, you can save packages to repositories on
various types of server, including FTP and HTTP servers. You can also just write
the packages to a repository in a local file system directory. A copy of your
package is also always cached on your local disk in the
folder. Monticello lets you save multiple versions of your program, merge
versions, go back to an old version, and browse the differences between
versions. In fact, Monticello is a distributed revision control system. This
means it allows developers to save their work on different places, not on a
single repository as it is the case with CVS or Subversion.
You can also send a
.mcz file by email. The recipient will have to place it
package-cache folder; she will then be able to use Monticello to
browse and load it.
Open the Monticello browser from the World menu (see Figure 0.35).
In the right-hand pane of the browser is a list of Monticello repositories,
which will include all of the repositories from which code has been loaded into
the image that you are using. The top list item is a local directory called the
package-cache. It caches copies of the packages that you have loaded or
published over the network. This local cache is really handy because it lets you
keep your own local history. It also allows you to work in places where you do
not have internet access, or where access is slow enough that you do not want to
save to a remote repository very frequently.
On the left-hand side of the Monticello browser is a list of packages that have a version loaded into the image. Packages that have been modified since they were loaded are marked with an asterisk. (These are sometimes referred to as dirty packages.) If you select a package, the list of repositories is restricted to just those repositories that contain a copy of the selected package.
PBE-LightsOut package to your Monticello browser using the
+ Package button and type
We think that the best way to save your code and share it is to create an account for your project in SmalltalkHub. SmalltalkHub is like GitHub: it is a web front-end to a HTTP Monticello server that lets you manage your projects. There is a public server at http://www.smalltalkhub.com/.
To be able to use SmalltalkHub you will need an account. Open the site in your browser. Then, click on the Join link and follow the instructions to create a new account. Finally, login to your account. Click on the + New project to create a new project. Fill in the information requested and click Register project button. You will be sent to your profile page, on the right side you will see the list of your projects and projects you watch by other coders. Click on the project you just created.
Under Monticello registration title label you will see a box containing a smalltalk message similar to
Copy the contents and go back to Pharo. Once your project has been created on
SmalltalkHub, you have to tell your Pharo system to use it. With the
PBE-LightsOut package selected, click the +Repository button in the
Monticello browser. You will see a list of the different Repository types that
are available. To add a SmalltalkHub repository select
will be presented with a dialog in which you can provide the necessary
information about the server. You should paste the code snippet you have copied
from SmalltalkHub (see Figure 0.36). This message tells
Monticello where to find your project online. You can also provide your user
name and password. If you do not, then Pharo will ask for them each time you try
to save into your online repository at SmalltalkHub.
Once you have accepted, your new repository should be listed on the right-hand side of the Monticello browser. Click on the Save button to save a first version of your Lights Out game on SmalltalkHub. Don't forget to put a comment so that you, or others, will have an idea of what your commit contains (see Figure 0.37).
To load a package into your image, open Monticello , select the repository where the package is located and click open button. It will open a new window with two columns, left one is the Package to be loaded, the right one is the version of the package to be loaded. Select the Package and the version you want to load and click the load button.
PBE-LightsOut repository you have just saved. You should see the
package you just saved.
Monticello has many more capabilities, which will be discussed in depth in Chapter 0.66 : Sharing Code and Source Control.
If you are already familiar with Git and Github there are several solutions to manage your projects with Git.
This blog posts provides a summary: http://blog.yuriy.tymch.uk/2015/07/pharo-and-github-versioning-revision-2.html#! There is a chapter in preparation on about how to use Git with Pharo. Request it on the Pharo mailing-list.
In this chapter you have seen how to create packages, classes and methods. In addition, you have learned how to use the System browser, the inspector, the debugger and the Monticello browser.
initializemethod is automatically executed after an object is created in Pharo. You can put any initialization code there.