LESSON 0002 · Collections & blocks · Pharo course

Lesson 0002 — Data Fluency

Collections & Blocks

A real app is mostly data moving through transformations. In Pharo that means blocks sent to collections. Six selectors carry almost all of it.

The win By the end you can take any list and transform it, filter it, find in it, and reduce it to a single value — without a single explicit loop. And you’ll teach your Counter a new trick that uses one.

1 · A block is an object

Square brackets make a block — a chunk of code saved for later, as a value you can pass around. Nothing inside runs until you send it value. (Pharo MOOC, blocks & iteration)

[ 2 + 2 ] value            → 4
[ :x | x * x ] value: 6    → 36   ":x is a parameter"

This matters because every loop in Pharo is just a message that takes a block. There is no for keyword — there’s do:.

2 · The six selectors

Recognise them by what shape comes back. All verified live in your image:

#(1 2 3 4 5) do:      [ :e | Transcript show: e printString ]  "side effects → returns the collection"
#(1 2 3 4 5) collect: [ :x | x * x ]      → #(1 4 9 16 25)   "same size, transformed (map)"
#(1 2 3 4 5) select:  [ :x | x even ]     → #(2 4)         "keep matches (filter)"
#(1 2 3 4 5) reject:  [ :x | x even ]     → #(1 3 5)       "drop matches"
#(3 1 4 1 5 9) detect: [ :x | x > 3 ]     → 4             "first match"
(1 to: 100) inject: 0 into: [ :sum :e | sum + e ]  → 5050  "fold to one value (reduce)"
The two that trip people up collect: vs select:collect changes each element (same count out); select keeps or discards whole elements (fewer out).
inject:into: — the seed follows inject:; the block is [ :accumulator :each | ... ]. It carries a running total across the collection.

3 · Quick recall — predict, then reveal

a. #(1 2 3 4) collect: [ :x | x + 1 ]

reveal

#(2 3 4 5)

collect: transforms each element; same size comes back.

b. #(1 2 3 4 5 6) select: [ :x | x > 3 ]

reveal

#(4 5 6)

select: keeps only elements whose block answers true.

c. (1 to: 4) inject: 1 into: [ :a :e | a * e ]  (note the seed is 1)

reveal

24

Running product: 1·1·2·3·4 = 24. That’s 4 factorial — inject:into: is how you fold a list into one number.

d. What message-type is inject:into:, and how many arguments does its block take?

reveal

keyword; two args

One keyword message #inject:into: with two arguments (seed, block). The block itself takes two parameters: accumulator and each.

4 · Hands-on — teach Counter to add a whole list (I’ll check it live)

Task · do this in your Counter-Esug image

Step 1. Add a method to Counter that bumps the count once for every number in a collection — reusing your own incrementBy::

addAll: aCollection
    aCollection do: [ :each | self incrementBy: each ]

Step 2. Predict, then evaluate in a Playground:

Counter new addAll: #(10 20 30); count
reveal prediction

60

Starts at 0, then do: sends incrementBy: 10, incrementBy: 20, incrementBy: 30. The cascade’s value is the last message, count.

Step 3. Add a test testAddAll to CounterTest in your usual style (self assert:equals:) proving it lands on 60.

Then say “done” — I’ll read addAll: through Iris, run CounterTest, and give feedback.

Bonus (optional) Rewrite addAll: with inject:into: instead of do: — hint: fold the collection to a total, then set count. Ask me to compare the two styles.

Primary source

This week: Pharo MOOC — the “Collections” and “Blocks” videos. Reference alongside: Collections & Blocks card and the deeper treatment in Pharo by Example.

Want to see any of these run on different data, or unsure why a shape comes back? Ask me — I’ll eval it in your image instantly.