17 Mrz

Smalltalk: Getting started with Pharo

Preface

This Post is working with the Pharo Distribution.

Install

$ curl get.pharo.org | bash

Now you can run any Smalltalk command:

$ ./pharo Pharo.image  eval "1+2"
3

The command line script pharo allows you to select a  Pharo Image to run. If you always want to ouse the same image, you can shorten the command line by changing the last line in pharo to:

"$DIR"/"pharo-vm/Pharo.app/Contents/MacOS/Pharo" --headless Pharo.image "$@"

If you additionally set an alias

alias pharo=$PWD/pharo

the command line is a little shorter:

$ pharo eval 1+2
3

Quick Sheet

To show the result of the command, select the command and press one of the following keys on MacOS with : 

d Do it
p Print it
i Install it

Commands:

Workspace open. Open an new Workspace Window CMD-d
SmalltalkImage current aboutThisSystem. Open the About Window CMD-d
Date today. Display current date CMD-p
Time now. Display current time CMD-p
SmalltalkImage current datedVersion. Current Date of Smalltalk Image  
DateAndTime today. Display date and time  
 HelpBrowser open.  Open Help  
     

Syntax

Syntax Elements

 

Basic types: Numbers

2. 2
20 factorial. 2432902008176640000
1000 factorial / 999 factorial. 1000
(1/3). (1/3)
(1/3) + (4/5). (17/15)
(1/3) asFloat. 0.3333333333333333
1 class. SmallInteger
1 class maxVal class. SmallInteger
(1 class maxVal + 1) class. LargePositiveInteger LargePositiveInteger

Basic types: Characters

$A.

$A.
$A class.  Character
$B charCode. 66
Character cr. Character cr.
Character space. Character space.
Character allByteCharacters. ‚

 !“#$%&“()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ‘

Basic types: Strings

 ‚Tutorial‘ size.  
‚abc‘ asUppercase.  
 ‚Hello World‘ reverse.  
 ‚Tutorial‘ at: 1.  

Basic types: Symbols

‚ProfStef‘ asSymbol. #ProfStef
#ProfStef asString. ‚ProfStef‘
(2 asString) == (2 asString). false
(2 asString) asSymbol == (2 asString) asSymbol. true

Basic types: Array

#(1 2 3). #(1 2 3)
#( 1 2 3 #(4 5 6)) size. 4
#(1 2 4) isEmpty. false
#(1 2 3) first. 1
#(‚hello‘ ‚World‘) at: 2 put: ‚Pharo‘; yourself. #(‚hello‘ ‚Pharo‘)

Basic types: Dynamic Array

{ (2+3) . (6*6) }. #(5 36)
{ (2+3) . (6*6) . ‚hello‘, ‚ world!‘} #(5 36 ‚hello world!‘)
{ (2+3) . (6*6) . ‚hello‘, ‚ world!‘} size. 3

Basic types: Unary messages

1 class. SmallInteger
false not. true
Time now. 6:16:30.386925 pm
Date today. 17 March 2017
Float pi. 3.141592653589793

Basic types: Binary messages

3 * 2. 6
Date today + 3 weeks. 7 April 2017
false | false. false
true & true. true
true & false. false
10 @ 100. (10@100)
10 <= 12. true
‚ab‘, ‚cd‘. ‚abcd‘
Date today < Date yesterday. false

Basic types: Keyword messages

The message is between:and: sent to the Number 4
4 between: 0 and: 10. true
1 max: 3. 3
Color r:1 g:0 b:0. Color red
The message is r:g:b: implemented on class Color. Note you can also write
Color
    r:1
    g:1
    b:0.
Color yellow

Basic types Execution order

Unary messages are executed first, then binary messages and finally keyword messages: Unary > Binary > Keywords
2 + 3 squared. 11
2 raisedTo: 3 + 2. 32
(0@0) class. Point
0@0 corner: 100@200. (0@0) corner: (100@200)
(0@0 corner: 100@200) class. Rectangle
„Between messages of similar precedence, expressions are executed from left to right“ nil
-3 abs negated reciprocal. (-1/3)

Message syntax Parentheses

<tbody „>

2 + 3 squared. 11
(2 + 3) squared. 25
2 raisedTo: 3 + 2. 32
(2 raisedTo: 3) + 2. 10
(0@0 extent: 100@200) bottomRight. (100@200)

Mathematical precedence

2 * 10 + 2. 22
Here the message * is sent to 2, which answers 20, then 20 receive the message + Remember that all messages always follow a simple left-to-right precedence rule, * without exceptions *.
2 + 2 * 10. 40
2 + (2 * 10). 22
8 – 5 / 2. (3/2)
(8 – 5) / 2. (3/2)
8 – (5 / 2). (11/2)

Blocks

Blocks are anonymous methods that can be stored into variables and executed on demand.
Blocks are delimited by square brackets: []
The next command does not open a Browser because the block is not executed.
[Workspace open]. [ Workspace open ]
Here is a block that adds 2 to its argument (its argument is named x):
[:x | x+2]. [ 😡 | x + 2 ]
We can execute a block by sending it value messages.
[:x | x+2] value: 5. 7
[Workspace open] value. a Workspace
[:x | x+2] value: 10. 12
[:x :y| x + y] value:3 value:5. 8

Block assignation

Blocks can be assigned to a variable then executed later.
Note that |b| is the declaration of a variable named ‚b‘ and that ‚:=‘ assigns a value to a variable.
Select the three lines then Print It:
|b|
    b := [:x | x+2].
    b value: 12. 14
14

Conditionals

No : 3 is less than 10

Conditionals are just messages sent to Boolean objects
Here the message is ifTrue:ifFalse
1 < 2
    ifTrue: [100]
    ifFalse: [42].
100
Transcript open.
3 > 10
    ifTrue: [Transcript show: ‚maybe there“s a bug ….‘]
    ifFalse: [Transcript show: ‚No : 3 is less than 10‘].
Transcript:

No : 3 is less than 10

 


Loops

1
1
4
7
1010
8
6
4
2
0

Loops are high-level collection iterators, implemented as regular methods.
Basic loops: to:do: to:by:do
1 to: 10 do:
   [:i | Transcript show: i asString; cr ].

2
3
4
5
6
7
8
9
10
1 to: 10 by: 3 do: [:i | Transcript show: i asString; cr]. 1
4
7
10
10 to: 0 by: -2 do: [:i | Transcript show: i asString; cr]. 10
8
6
4
2
0

Iterators

The message do: is sent to a collection of objects (Array, Set, OrderedCollection), evaluating the block for each element. Here we want to print all the numbers on the Transcript (a console)
#(11 38 3 -2 10) do: [:each | Transcript show: each printString; cr]. 11
38
3
-2
10
#(11 38 3 -2 10)
Some other really nice iterators
#(11 38 3 -2 10) collect: [:each | each abs]. #(11 38 3 2 10)
#(11 38 3 -2 10) collect: [:each | each odd]. #(true false true false false)
#(11 38 3 -2 10) select: [:each | each odd]. #(11 3)
#(11 38 3 -2 10) select: [:each | each > 10]. #(11 38)
#(11 38 3 -2 10) reject: [:each | each > 10]. #(3 -2 10)
#(11 38 3 -2 10)
   do: [:each | Transcript show: each printString]
   separatedBy: [Transcript show: ‚.‘].
11.38.3.-2.10)

Instantiation

Objects are instances of their class. Usually, we send the message #new to a class for creating an instance of this class.
The message #allInstances sent to a class answers an Array with all instances of this class.
For example, let’s look at how many instances of SimpleButtonMorph exist:
SimpleButtonMorph allInstances size. 0
Now create a new instance of it:
SimpleButtonMorph new
    label: ‚A nice button‘;
    openCenteredInWorld.
a SimpleButtonMorph(777874944)
See the button centered on the world ? The list of all instances should contains one more instance:
SimpleButtonMorph allInstances size. 0
Let’s play with it:
SimpleButtonMorph allInstances last
    label: ‚ProfStef is cooooool !‘;
    color: Color cyan.
 
Let’s delete it and ask the system to clean the memory:
SimpleButtonMorph allInstances last
    delete.
 
Smalltalk garbageCollect. 16777200
SimpleButtonMorph allInstances size. 0
Click on the button to go to next lesson:
SimpleButtonMorph new
    label: ‚Go to next lesson‘;
    target: [ProfStef next.
             SimpleButtonMorph allInstances last
             delete];
    actionSelector: #value;
    openCenteredInWorld.
a SimpleButtonMorph(924529408)

Reflection

You can inspect and change the system at runtime. Take a look at method #ifFalse:ifTrue: source code of class True:
(True>>#ifFalse:ifTrue:) definition. ‚ifFalse: falseAlternativeBlock ifTrue: trueAlternativeBlock
„Answer the value of trueAlternativeBlock. Execution does not
actually reach here because the expression is compiled in-line.“^trueAlternativeBlock value‘
Or just its comment:
(True>>#ifFalse:ifTrue:) comment. ‚“Answer the value of trueAlternativeBlock. Execution does not
actually reach here because the expression is compiled in-line.“‚
Here’s all the methods I implement:
ProfStef selectors. #(#close #go #first #tutorial:lessonAt: #next #tutorial:lesson: #previous #player #open #tutorialPositionString #lessonView: #helpBrowserWindow #lessonView #showCurrentLesson #last #goOn: #player: #tutorialSizeString)
Let’s create a new method to go to the next lesson:
ProfStef class compile:’goToNextLesson self next‘. #goToNextLesson
Wow ! I can’t wait to use my new method !
ProfStef goToNextLesson. ProfStef

 

So cool, isn’t it ? Before going further, let’s remove this method:
ProfStef respondsTo: #goToNextLesson. true
ProfStef class removeSelector: #goToNextLesson. ProfStef class
ProfStef respondsTo: #goToNextLesson. true
Then move forward:
ProfStef default executeMethod: (ProfStef lookupSelector:#next). a ProfStef

Pharo environment

Pharo is full of objects. There are windows, text, numbers, dates, colors, points and much more. You can interact with objects in a much more direct way than is possible with other programming languages. Every object understands the message ‚explore‘. As a result, you get an Explorer window that shows details about the object.
Date today explore. 17 March 2017
This shows that the date object consists of a point in time (start) and a duration (one day long).
ProfStef explore. ProfStef
You see, ProfStef class has a lot of objects. Let’s take a look at my code:
ProfStef browse. a Nautilus

FAQ

What does 0 @ 0 mean?

0@0 represents a Point object with x and y coordinates both set to 0.

In fact, 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).