LESSON 0001 · Syntax fluency · Pharo course

Lesson 0001 — Syntax Fluency

Reading Any Line of Pharo

Master one rule — unary > binary > keyword — and every line of Pharo, including your own Counter, stops being a puzzle.

The win By the end you can look at any Pharo expression and say out loud, in the right order, which message is sent to what — then predict the result before you run it. This is the bedrock of writing an app fluently.

1 · Everything is a message

Pharo has almost no syntax. There are no operators, no if statements, no for loops built into the language. There is one idea: you send a message to an object (the receiver), and it answers an object back. Even 3 + 4 is “send the message + with argument 4 to the object 3.” (Pharo by Example, “Expressions”)

Messages come in exactly three shapes:

TypeLooks likeFrom your Counter
Unaryreceiver selectorcounter increment
Binaryreceiver op argcount + 1
Keywordreceiver key: argcounter incrementBy: 5

You already used all three when you wrote Counter — you just may not have named them.

2 · The one rule of precedence

Memorise this Unary binds tightest, then binary, then keyword. Within the same level, evaluate left to right. There is no maths precedence.

So 2 + 3 * 4 is not 14. Both + and * are binary, so it runs strictly left to right: (2 + 3) * 4. Verified live in your image:

2 + 3 * 4        → 20

And a unary always jumps the queue ahead of a binary:

2 + 3 factorial  "factorial is unary → binds first: 2 + (3 factorial) = 2 + 6"
                 → 8

3 · Quick recall — predict before revealing

Say each answer out loud first. Retrieval is what makes it stick — don’t peek early.

a. 10 - 3 - 2

reveal

5

All binary, left→right: (10 - 3) - 2. Not 10 - (3 - 2).

b. 1/2 + 1/3  (all of / and + are binary)

reveal

(1/2)

Left→right: ((1/2) + 1) / 3 = (3/2) / 3 = 1/2. A famous gotcha — it is not 5/6. Parenthesise: (1/2) + (1/3) gives 5/6.

c. $A asInteger

reveal

65

$A is a Character literal; asInteger is a unary message asking for its code point.

d. Which single message is sent here — name its selector: arr at: 1 put: 99

reveal

#at:put:

One keyword message with two arguments — not two messages. The selector is the whole thing: at:put:.

4 · Cascades — the semicolon

Your testDecrement already uses one:

counter increment; increment; decrement.

A cascade (;) sends several messages to the same receiver — the receiver of the first message, here counter. Without cascades you’d repeat counter three times. The value of a cascade is the value of its last message.

Don’t confuse c increment; count — cascade, sends count to c.
c increment count — chain, sends count to whatever increment returned.

5 · Hands-on — extend your real app (I’ll check it live)

Task · do this in your Pharo image

Step 1. Give Counter a way down. In the System Browser, open Counter (package Counter) and add:

decrementBy: anInteger
    count := count - anInteger

Step 2. In a Playground, predict the result of this cascade, then evaluate it. (count: is your setter; the cascade sends three messages to one new Counter.)

Counter new count: 10; decrementBy: 3; count

Step 3. Add a test method to CounterTest that proves it, mirroring your existing style (self assert:equals:).

Then tell me “done”. I’ll read your method through Iris, run CounterTest, and give you feedback in seconds. Predict the Step 2 value before you run it:

reveal Step 2 answer

7

10 - 3 = 7; the cascade’s value is its last message, count. Three keyword/unary messages all sent to the one new Counter.

Primary source

Watch/read one thing this week: the Pharo MOOC, Week 1 — “Syntax, Messages, Cascades.” It is by the Pharo team and covers exactly this lesson in ~15 minutes of video. Book alternative: Pharo by Example, the expressions/syntax chapter.

Stuck, curious, or want to go deeper on any line above? Ask me — I’m your teacher. I can eval anything in your image on the spot. Keep the Syntax Reference Card open beside you.