- Dynamically typed
- REPL everywhere
1 + 2
>>> 3
1.1 * 2.3
>>> 2.53
Tips: in Pharo all the mathematic operators (+, '-', ...) can be defined on any class.
4 ** 2
>>> 16
In Pharo you can also use raisedTo: in addition to **.
4 raisedTo: 2
>>> 16
57/5
>>> 11.4
57 // 5
>>> 11
Tips: Use the example finder to discover the message based on the arguments.
x = 3
x = x + 2
x
| x |
x := 3
x := x + 2
x
>>> 5
| x | declares that we will use a temporary variable.
Note that the Playground declares automatically variable for you.
x := y := 3.
x + y
>>> 6
Pharo does not support multiple assignments such as the following ones in Python.
x, y = 6,4
(2 ** 90) numberOfDigits
>>28
1 class
>>>SmallInteger
1 class maxVal
>>xxx
Largest small integer
(1 class maxVal) + 1
>>xxx
((1 class maxVal) + 1) class
>> LargePositiveInteger
In Pharo arithmetic operations are plain messages. There is no precedence we should put parentheses to disambiguate.
how python is doing for x + y * z?
####Internal console
Transcript show: 'hello world'.
'Hello world' traceCr.
####External console
STdio 'hello world'
We should do something here.
Pharo offers a really large set of numerical functions. We will not list them all.
- abs
- int
- mix
- max
- round(x,n)
Tips: there is no variable number of argument in Pharo.
- floor
- sqrt
- cos, sin, tan
- atan, asin, acos
arcTan
Float pi
Tips: Browse the class Float and SmallInteger
By default Pharo manipulates fractions.
To create a fraction we use the message /.
(1/3) + (2/3)
>>> 1
(1/2) numerator
>>> 1
testReciprocal
self
assert: (1 / 2) reciprocal equals: 2;
assert: (3 / 4) reciprocal equals: 4 / 3;
assert: (-1 / 3) reciprocal equals: -3;
assert: (-3 / 5) reciprocal equals: -5 / 3
Pharo offers a really nice set of powerful tool. The first one is the Finder.
In Pharo booleans true and false are instances of the class True and the class False.
(1 > 3)
>>> False
(1 > 3)
>>> false
false class
>>> False
| x |
x := Object new.
x == x
>>> true
Object new =~ Object new
>>> true
Pharo offers default comparison messages: <, >, >=, =, <=.
All subclasses of Magnitude are able to redefine such messages.
(1 < 5) & (5<10)
>>> true
(5 < 1) and: [ 1/0 ]
>>> true
5 between: 1 and: 10
>>> true
(1 < 5) | false
>>> true
(1 < 5) or: [ 1/ 0 ]
>>> true
Explanation: in Pharo there are only objects and messages. ifTrue:, ifFalse:, ifTrue:ifFalse:,.. are all messages sent to booleans
x ifTrue: [ ]
x ifFalse: [ ]
x
ifTrue: [ ]
ifFalse: [ ]
x
ifFalse: [ ]
ifTrue: [ ]
In Pharo a string is a collection of Character instances. A string is delimited by a single quote.
A symbol is a unique string.
"hello world"
>>> "hello world"
'hello world'
>>> 'hello world'
The class String defines a large number of methods.
Contrary to Python, in Pharo, getting the length of a string is just sending the message size to the string.
len("hello world")
>>> 11
'hello world' size
>>> 11
To concatenate two strings and get a new one, we send the message comma , to the first string.
The following example creates a string with all the alphabetic letters.
x = ""
for i in range(97, 122):
x = x+chr(i)
>>>xxx
| alpha |
alpha :=''.
(97 to: 122) do: [ :c | alpha := alpha, c asCharacter asString ].
alpha "'abcdefghijklmnopqrstuvwxyz'"
It is better to use a stream to avoid to create 26 strings that are then discarded. The Pharo idiomatic way is the following one: first we create a stream on a string and we place one by one the character using the nextPut: message.
String streamContents: [ :st |
(97 to: 122) do: [ :c | st nextPut: c asCharacter ]].
>>> 'abcdefghijklmnopqrstuvwxyz'
In Pharo the first element of a string starts at index 1 and we can access element using the message at:.
'Pharo is c00l' at: 5
>>> $o
st = "Pharo is cool"
for i in range(0, len(st):
print("Char :, i, st[i])
>>>
A first variation using at:.
| st |
st := 'Pharo is cool'.
1 to: st size do: [ :i |
st traceCr: ('Char {1} is {2}.' format: { i . st at: i }) ]
A second variation using withIndexDo:.
| st |
st := 'Pharo is cool'.
st withIndexDo: [ :c :i |
st traceCr: ('Char {1} is {2}.' format: { i . c }) ]
Char 1 is P.
Char 2 is h.
Char 3 is a.
Char 4 is r.
Char 5 is o.
Char 6 is .
Char 7 is i.
Char 8 is s.
Char 9 is .
Char 10 is c.
Char 11 is o.
Char 12 is o.
Char 13 is l.
'Pharo is c00l' allButFirst: 6
"'is c00l'"
'Pharo is c00l' copyFrom: 11 to: 12
"'00'"
Pharo offers many different loops and conditional loops. Such loops can be traditional loops using explicit index access or iterators.
1 to: 100 by: 3 do: [:i | i traceCr]
1 to: 100 by: 3 do: [:i | i traceCr]
for i in range(1,6):
print(i)
1 to: 6 do: [ :i | i traceCr ]
When you have an expression to execute a number of times, you can also use the message timesRepeat: as follows:
6 timesRepeat: [ 1 traceCr ]
(1 to: 6) do: [ :i | i traceCr ]
end = 10
count = 1
while count <= end
print("A")
count = count + 1
print("end")
| end count |
end := 10.
count := 1.
[ count <= end ] whileTrue:
[ 'A' traceCr.
count := count + 1
]
[] whileFalse: []
Pharo is a pure object-oriented language. You can only define methods in a class. Methods can simply return a value (and be similar to functions) or change the state of the object to which they are applied. By default a method returns the receiver of the message.
Imagine that we would like to compute the body mass index defined as the quotient of the height by the square of the weigth.
def bodyMassIndex(height, weigth)
return int(round(weigth / height** 2),0)
In Pharo we will define a class named Calculator
Object << Calculator
package: 'Pyt'
bodyMaxIndexFor: height and: weigth
^ ((weigth / (height * height)) rounded
The character ^ is the method return expression.
Pharo also offers lexical closure named lambda in Python. A lexical closure in Pharo is like an anonymous method which is not defined in a class.
Closures are central to Pharo, most of the control flow mechanism such as conditionals, loops, and iterators are based on closures.
f=lambda x : -x + 4
f(3)
>>> 1
In Pharo closures are objects that are executed sending them the messages value:.
f := [:x | -x + 4].
f value: 3
>>> 1
g := [:x :y| -x + y].
g value: 3 value: 4
>>> 1
Pharo defines many different data structures such as Set, Array, OrderedCollection, Dictionary, Bag...
Now we will show how Python lists are close to Pharo's ordered collections.
x=[10,12,12,12,13,14,14,15]
x.count(12)
>>> 3
Ordered collection instances can hold really large amount of objects. For example in the Moose reengineering platform it is frequent to hold more than 600,000 objects.
Now in script creating ordered collections is verbose so we will convert arrays as ordered collection. The main difference between Array and OrderedCollection is that Array have fixed size and cannot grow dynamically.
x=[10,12,12,12,13,14,14,15]
x.count(12)
>>> 3
x := #(10 12 12 12 13 14 14 15) asOrderedCollection.
x occurrencesOf: 12
>>> 3
Pharo does not propose predefined ways to create lists based on range but we can create intervals which are object representing range.
pair=range(0,20,2)
pair=(0 to: 20 by: 2)
Another way is to convert an interval into an ordered collection.
pair=(0 to: 20 by: 2) asOrderedCollection
Here is an explicit way to create an OrderedCollection with all the multiples of 7 and 9 from 0 to 10000. This way can be easily generalized
| col |
col := OrderedCollection new.
0 to: 10000 do: [ :each |
(each rem: 7) isZero
and: [ (each rem: 9) isZero
ifTrue: [ col add: each ] ] ].
col
The following program builds a new list (in fact it builds many intermediate lists).
pair = []
for i in range(0,20,2):
pair=pair+[i]
An equivalent growing the original collection is
pair := OrderedCollection new.
(0 to: 20 by: 2) do: [ :el |
pair add: el ]
Pharo's OrderedCollection offers a large API. For example here are all the methods for just the addition of an element:
addAllFirstUnlessAlreadyPresent:add:after:add:afterIndex:add:beforeIndex:addFirst:add:addAllFirst:addLast:add:before:addAll:addAllLast:
The following script generates the list taking into account locally defined methods of the class OrderedCollection.
OrderedCollection offers way to insert, delete, reverse, sort, and verify various predicates.