﻿WEBVTT

00:00:00.440 --> 00:00:04.440 align:middle
In this session, I'll talk
about iterators and collections.

00:00:04.600 --> 00:00:09.000 align:middle
We'll see how to easily browse collections
thanks to iterators in Pharo.

00:00:09.160 --> 00:00:13.000 align:middle
You'll understand
the power of iterators in Pharo.

00:00:13.160 --> 00:00:17.640 align:middle
I'll review the main iterators
you may use.

00:00:17.800 --> 00:00:19.360 align:middle
An example first:

00:00:19.520 --> 00:00:22.680 align:middle
this is the code
you should write in Java

00:00:23.880 --> 00:00:25.320 align:middle
to browse a collection.

00:00:25.480 --> 00:00:28.160 align:middle
I'll browse the collection persons

00:00:28.320 --> 00:00:31.920 align:middle
to extract the list of people
(object persons).

00:00:32.480 --> 00:00:35.240 align:middle
In Pharo, you'd write this code.

00:00:35.400 --> 00:00:39.880 align:middle
You'd use the iterator collect.
We'll talk about it later.

00:00:40.040 --> 00:00:43.360 align:middle
You collect all the names of people.

00:00:43.520 --> 00:00:47.920 align:middle
By the way, in Java 8,
the latest version of Java,

00:00:48.080 --> 00:00:51.120 align:middle
they've introduced blocks,

00:00:51.280 --> 00:00:53.640 align:middle
the equivalent of lexical closures.

00:00:53.800 --> 00:00:57.000 align:middle
As a result, the syntax
is close to Pharo's.

00:00:57.160 --> 00:01:00.200 align:middle
But in Pharo, we've had it
since the beginning.

00:01:00.360 --> 00:01:02.440 align:middle
It's at the heart of the language.

00:01:02.600 --> 00:01:07.320 align:middle
It gives big power of expression
to a programmer.

00:01:08.200 --> 00:01:11.320 align:middle
There are plenty of iterators.

00:01:11.480 --> 00:01:16.400 align:middle
First, there's collect. What's the use
of collect when sent to a collection?

00:01:16.560 --> 00:01:20.240 align:middle
This is a collection
of positive and negative numbers.

00:01:20.400 --> 00:01:23.200 align:middle
I send the message collect,
and I pass a block.

00:01:23.360 --> 00:01:25.560 align:middle
Whenever you browse the collection,

00:01:25.720 --> 00:01:30.160 align:middle
the parameter of the block
will be in turn: 2, -3, 4, etc.

00:01:30.320 --> 00:01:33.760 align:middle
Then you send the message abs,
for absolute.

00:01:33.920 --> 00:01:36.840 align:middle
It means you want the absolute value
of this number.

00:01:37.000 --> 00:01:40.720 align:middle
Once you've applied the block
to every element of the collection,

00:01:40.880 --> 00:01:43.360 align:middle
you aggregate the results in a new one.

00:01:43.520 --> 00:01:46.520 align:middle
The result returned by collect
is a new collection.

00:01:46.680 --> 00:01:50.160 align:middle
The block has been applied
to every element of the collection:

00:01:50.320 --> 00:01:53.800 align:middle
the absolute value of 2,
the absolute value of -3, which is 3,

00:01:53.960 --> 00:01:58.480 align:middle
the absolute value of 4, 4,
the absolute value of -35, 35.

00:01:58.640 --> 00:02:00.320 align:middle
and the absolute value of 4, 4.

00:02:01.080 --> 00:02:04.200 align:middle
The interesting thing
which you must remember

00:02:04.360 --> 00:02:06.760 align:middle
is that you must think object.

00:02:06.920 --> 00:02:09.720 align:middle
We ask the collection
to do something for us.

00:02:09.880 --> 00:02:14.440 align:middle
The collection
browses its own elements by itself.

00:02:14.600 --> 00:02:17.240 align:middle
We provide the processing
of each element.

00:02:17.400 --> 00:02:20.400 align:middle
That's where the secret
of iterators lies.

00:02:21.040 --> 00:02:23.280 align:middle
This is another example of collect.

00:02:23.440 --> 00:02:27.000 align:middle
This is a collection
to which I send the message collect.

00:02:27.160 --> 00:02:31.000 align:middle
In the block, I'll ask every time

00:02:31.760 --> 00:02:34.200 align:middle
whether the element is odd.

00:02:34.360 --> 00:02:37.160 align:middle
I'll aggregate all the results:

00:02:37.320 --> 00:02:40.080 align:middle
false, true, false, true.

00:02:43.720 --> 00:02:47.480 align:middle
Of course, you can write

00:02:47.640 --> 00:02:50.400 align:middle
what you'd usually write
in other languages

00:02:50.560 --> 00:02:52.680 align:middle
devoid of blocks and iterators.

00:02:52.840 --> 00:02:55.160 align:middle
You could write: I take the collection,

00:02:55.760 --> 00:02:58.680 align:middle
I build a collection of results.

00:02:59.320 --> 00:03:03.560 align:middle
I'll browse from one
to the collection size.

00:03:03.720 --> 00:03:04.960 align:middle
I'll use do.

00:03:05.120 --> 00:03:08.920 align:middle
I browse the collection
and add things in the collection result.

00:03:09.080 --> 00:03:12.400 align:middle
You could write all this.
It's exactly the same.

00:03:12.560 --> 00:03:15.440 align:middle
It's up to you.
Do you want to write something simple

00:03:15.600 --> 00:03:19.000 align:middle
or something complicated?
That's the question.

00:03:19.160 --> 00:03:22.000 align:middle
I much prefer the first solution.

00:03:24.200 --> 00:03:27.120 align:middle
In the hierarchy
of the Pharo collections,

00:03:28.320 --> 00:03:32.000 align:middle
there's something crucial:
all collections are polymorphic

00:03:32.160 --> 00:03:35.080 align:middle
and inherit the class.
So you have a common API.

00:03:35.240 --> 00:03:39.720 align:middle
The upside is that the iterators
will also work

00:03:39.880 --> 00:03:42.840 align:middle
with most collections.

00:03:44.480 --> 00:03:48.080 align:middle
It's really about thinking object:

00:03:48.240 --> 00:03:51.280 align:middle
you tell the collection
to iterate on itself.

00:03:51.440 --> 00:03:54.800 align:middle
We don't know whether
we're using a dictionary.

00:03:54.960 --> 00:03:58.880 align:middle
We don't want to know about the internal
logic of keys, values, etc.

00:03:59.400 --> 00:04:02.320 align:middle
So you ask the collection to be nice

00:04:02.480 --> 00:04:04.960 align:middle
and to process its elements.

00:04:06.640 --> 00:04:11.320 align:middle
Many iterators can be used to do this.
We already saw do: and collect:.

00:04:11.480 --> 00:04:14.280 align:middle
There are more:
select:, reject:, detect:, etc.

00:04:14.440 --> 00:04:17.840 align:middle
We'll study a few of these
later in this course.

00:04:19.320 --> 00:04:22.760 align:middle
do: is the simplest iterator.

00:04:22.920 --> 00:04:26.960 align:middle
It browses every element of the
collection: they're in the transcript.

00:04:27.120 --> 00:04:30.560 align:middle
We already studied it many times.

00:04:30.720 --> 00:04:33.320 align:middle
This is a new iterator: select:.

00:04:33.480 --> 00:04:36.560 align:middle
I want to get all the elements
of the collection

00:04:36.720 --> 00:04:38.360 align:middle
which match a criterion.

00:04:38.520 --> 00:04:41.960 align:middle
I want all the odd elements
of the collection.

00:04:42.120 --> 00:04:45.040 align:middle
I send select: to the collection.

00:04:45.200 --> 00:04:46.440 align:middle
I pass a block.

00:04:46.600 --> 00:04:49.560 align:middle
Whenever the value of the block is true,

00:04:49.720 --> 00:04:53.080 align:middle
the element concerned
is added to the result collection.

00:04:55.040 --> 00:04:58.080 align:middle
It's exactly the same as select: #odd.

00:04:58.240 --> 00:05:01.120 align:middle
When I have a block here

00:05:01.280 --> 00:05:05.400 align:middle
or what amounts to a single message send
to the element of the collection,

00:05:05.560 --> 00:05:06.920 align:middle
the block's parameter,

00:05:07.080 --> 00:05:10.760 align:middle
I can display the name of the message
to be sent as a symbol.

00:05:10.920 --> 00:05:12.480 align:middle
It's even shorter.

00:05:12.640 --> 00:05:16.000 align:middle
It only works with unary messages.

00:05:17.920 --> 00:05:20.880 align:middle
You may use other types of iterators
such as reject:.

00:05:21.040 --> 00:05:24.160 align:middle
I want to get rid of the odd elements
of the collection.

00:05:24.320 --> 00:05:27.520 align:middle
In the results,
I'll only have even elements left.

00:05:28.520 --> 00:05:30.160 align:middle
Or I want to use detect:.

00:05:30.320 --> 00:05:34.000 align:middle
I want to detect the first element
that matches a criterion:

00:05:34.160 --> 00:05:37.000 align:middle
the value of the block must be true.

00:05:37.160 --> 00:05:40.920 align:middle
I want the first odd element
of the collection: 11.

00:05:42.320 --> 00:05:46.880 align:middle
Sometimes, you want to detect the first
element that matches a criterion.

00:05:47.040 --> 00:05:50.120 align:middle
If there isn't any,
you want a default value:

00:05:50.280 --> 00:05:52.440 align:middle
detect: ifNone:.

00:05:52.600 --> 00:05:57.360 align:middle
If there is no match,
it will return the value of this block,

00:05:57.520 --> 00:05:59.640 align:middle
which is 0.

00:05:59.800 --> 00:06:04.800 align:middle
There are other iterators
which make a programmer's life easier.

00:06:04.960 --> 00:06:06.800 align:middle
For instance, anySatisfy:

00:06:06.960 --> 00:06:10.600 align:middle
tests if one object
meets the criterion.

00:06:10.760 --> 00:06:13.320 align:middle
I can test if all objects
meet the criterion.

00:06:13.480 --> 00:06:17.320 align:middle
I can browse the collection in reverse,
from the end.

00:06:17.480 --> 00:06:22.360 align:middle
I can browse the collection with an
index or browse its elements in pairs.

00:06:22.520 --> 00:06:26.480 align:middle
I can browse all the possible
circular permutations, etc.

00:06:26.640 --> 00:06:28.960 align:middle
There are many iterators.

00:06:29.120 --> 00:06:31.480 align:middle
You can build new ones, too.

00:06:31.640 --> 00:06:35.320 align:middle
I want to browse one collection 1 2 3

00:06:35.480 --> 00:06:38.440 align:middle
as well as another collection.

00:06:38.600 --> 00:06:42.600 align:middle
In the block do:, I have
:x and :y which are two parameters.

00:06:42.760 --> 00:06:46.840 align:middle
:x is an element
of the first collection;

00:06:47.000 --> 00:06:48.920 align:middle
y:, of the second.

00:06:49.080 --> 00:06:51.080 align:middle
I can multiply these elements:

00:06:51.240 --> 00:06:53.720 align:middle
the results are 10, 40, and 90.

00:06:54.840 --> 00:06:59.440 align:middle
Of course, with this iterator, the two
collections must be of the same length.

00:07:01.360 --> 00:07:04.720 align:middle
There are other ways:

00:07:04.880 --> 00:07:08.120 align:middle
here I use do: separatedBy:.

00:07:08.280 --> 00:07:11.280 align:middle
I have a collection.
I browse every element.

00:07:11.440 --> 00:07:14.040 align:middle
Whenever one element is browsed,

00:07:14.200 --> 00:07:17.680 align:middle
I give value to one block
which matches a comma.

00:07:17.840 --> 00:07:20.480 align:middle
So I can browse a,

00:07:20.640 --> 00:07:23.320 align:middle
display a comma, then b,
then a comma, then c.

00:07:23.480 --> 00:07:26.400 align:middle
Between each element,
I perform one action.

00:07:28.880 --> 00:07:31.640 align:middle
This is the iterator groupedBy:.

00:07:31.800 --> 00:07:36.040 align:middle
I can use it to group
the elements of a collection

00:07:36.200 --> 00:07:37.720 align:middle
with respect to criteria.

00:07:37.880 --> 00:07:42.040 align:middle
I sent this message
to the collection 1 2 3 4 5 6 7.

00:07:42.200 --> 00:07:45.480 align:middle
As a result, I get a dictionary:

00:07:47.000 --> 00:07:50.440 align:middle
all the elements which returned false
to this criterion,

00:07:50.600 --> 00:07:52.800 align:middle
which was #even, the even elements.

00:07:52.960 --> 00:07:56.000 align:middle
As you can see,
I have all the odd elements.

00:07:56.160 --> 00:07:59.520 align:middle
All the even elements returned true.

00:08:02.280 --> 00:08:04.520 align:middle
It's often the case, when you compute,

00:08:04.680 --> 00:08:07.720 align:middle
that you tend to nest collections
in collections.

00:08:07.880 --> 00:08:11.440 align:middle
You end up with huge nesting levels.

00:08:11.600 --> 00:08:14.480 align:middle
This is an example built by hand.

00:08:14.640 --> 00:08:17.560 align:middle
These are collections
nested in collections.

00:08:17.720 --> 00:08:22.200 align:middle
We'd like to flatten the collection:
to even everything out.

00:08:22.880 --> 00:08:26.960 align:middle
In Pharo, there's an easy way:

00:08:27.120 --> 00:08:29.120 align:middle
the flatCollect: iterator.

00:08:29.280 --> 00:08:33.520 align:middle
I browse the elements and build a new
collection where everything is even.

00:08:35.240 --> 00:08:38.280 align:middle
You end up
with the 1 2 3 4 5 6 collection.

00:08:38.440 --> 00:08:40.600 align:middle
The nesting levels are all gone.

00:08:44.040 --> 00:08:48.520 align:middle
I don't intend to tell you
about every Pharo iterator.

00:08:48.680 --> 00:08:52.480 align:middle
It'd be long and unpleasant.
I just want to show there are many.

00:08:52.640 --> 00:08:54.280 align:middle
You can define your own

00:08:54.440 --> 00:08:57.760 align:middle
by reading about collection classes.

00:08:57.920 --> 00:08:59.560 align:middle
Find out about them.

00:08:59.720 --> 00:09:02.960 align:middle
For instance, start
with the iterators you already know.

00:09:03.120 --> 00:09:05.840 align:middle
You can wonder how do: is implemented.

00:09:06.000 --> 00:09:08.600 align:middle
I look for it
in the hierarchy of collections.

00:09:08.760 --> 00:09:13.760 align:middle
I realize it's implemented
as SequenceableCollection.

00:09:13.920 --> 00:09:16.680 align:middle
The method do:
selects aBlock as its parameter.

00:09:16.840 --> 00:09:19.400 align:middle
This is the collection's implementation.

00:09:19.560 --> 00:09:23.320 align:middle
1 to: self size do: [i:| aBlock.

00:09:23.480 --> 00:09:26.600 align:middle
I evaluate the block
used as the parameter

00:09:26.760 --> 00:09:29.840 align:middle
by passing it the element i.

00:09:30.000 --> 00:09:31.160 align:middle
It's very easy.

00:09:31.960 --> 00:09:37.280 align:middle
In Pharo, iterators are very powerful,
as we just saw.

00:09:37.440 --> 00:09:41.880 align:middle
Every collection
supports the iterators polymorphically.

00:09:42.040 --> 00:09:45.200 align:middle
Programmers use iterators

00:09:45.360 --> 00:09:48.240 align:middle
which get implemented
by collection classes

00:09:49.000 --> 00:09:51.720 align:middle
according to the collection
they represent.

00:09:52.520 --> 00:09:55.200 align:middle
You can define new ones.
It's very interesting.

00:09:55.360 --> 00:09:58.840 align:middle
I can define my own iterators
on the collection classes.

00:10:00.480 --> 00:10:04.480 align:middle
There's a small nuance for those
who know the iterator design pattern:

00:10:05.160 --> 00:10:10.480 align:middle
a developer cannot choose
when to go to the next element.

00:10:10.640 --> 00:10:14.120 align:middle
The collection decides it internally.

00:10:14.280 --> 00:10:17.160 align:middle
next isn't sent directly
to the iterator.

00:10:17.320 --> 00:10:20.920 align:middle
It's a nuance for those
who know the Iterator design pattern.

00:10:21.520 --> 00:10:25.720 align:middle
Iterators are very powerful.

00:10:25.880 --> 00:10:28.960 align:middle
They're a programmer's best friends.

00:10:29.120 --> 00:10:31.120 align:middle
It makes writing programs easier:

00:10:31.280 --> 00:10:34.280 align:middle
you can write short, simple,
and elegant code.

00:10:34.440 --> 00:10:37.320 align:middle
It ensures

00:10:37.960 --> 00:10:40.720 align:middle
data encapsulation in a collection.