1 00:00:00,440 --> 00:00:04,440 In this session, I'll talk about iterators and collections. 2 00:00:04,600 --> 00:00:09,000 We'll see how to easily browse collections thanks to iterators in Pharo. 3 00:00:09,160 --> 00:00:13,000 You'll understand the power of iterators in Pharo. 4 00:00:13,160 --> 00:00:17,640 I'll review the main iterators you may use. 5 00:00:17,800 --> 00:00:19,360 An example first: 6 00:00:19,520 --> 00:00:22,680 this is the code you should write in Java 7 00:00:23,880 --> 00:00:25,320 to browse a collection. 8 00:00:25,480 --> 00:00:28,160 I'll browse the collection persons 9 00:00:28,320 --> 00:00:31,920 to extract the list of people (object persons). 10 00:00:32,480 --> 00:00:35,240 In Pharo, you'd write this code. 11 00:00:35,400 --> 00:00:39,880 You'd use the iterator collect. We'll talk about it later. 12 00:00:40,040 --> 00:00:43,360 You collect all the names of people. 13 00:00:43,520 --> 00:00:47,920 By the way, in Java 8, the latest version of Java, 14 00:00:48,080 --> 00:00:51,120 they've introduced blocks, 15 00:00:51,280 --> 00:00:53,640 the equivalent of lexical closures. 16 00:00:53,800 --> 00:00:57,000 As a result, the syntax is close to Pharo's. 17 00:00:57,160 --> 00:01:00,200 But in Pharo, we've had it since the beginning. 18 00:01:00,360 --> 00:01:02,440 It's at the heart of the language. 19 00:01:02,600 --> 00:01:07,320 It gives big power of expression to a programmer. 20 00:01:08,200 --> 00:01:11,320 There are plenty of iterators. 21 00:01:11,480 --> 00:01:16,400 First, there's collect. What's the use of collect when sent to a collection? 22 00:01:16,560 --> 00:01:20,240 This is a collection of positive and negative numbers. 23 00:01:20,400 --> 00:01:23,200 I send the message collect, and I pass a block. 24 00:01:23,360 --> 00:01:25,560 Whenever you browse the collection, 25 00:01:25,720 --> 00:01:30,160 the parameter of the block will be in turn: 2, -3, 4, etc. 26 00:01:30,320 --> 00:01:33,760 Then you send the message abs, for absolute. 27 00:01:33,920 --> 00:01:36,840 It means you want the absolute value of this number. 28 00:01:37,000 --> 00:01:40,720 Once you've applied the block to every element of the collection, 29 00:01:40,880 --> 00:01:43,360 you aggregate the results in a new one. 30 00:01:43,520 --> 00:01:46,520 The result returned by collect is a new collection. 31 00:01:46,680 --> 00:01:50,160 The block has been applied to every element of the collection: 32 00:01:50,320 --> 00:01:53,800 the absolute value of 2, the absolute value of -3, which is 3, 33 00:01:53,960 --> 00:01:58,480 the absolute value of 4, 4, the absolute value of -35, 35. 34 00:01:58,640 --> 00:02:00,320 and the absolute value of 4, 4. 35 00:02:01,080 --> 00:02:04,200 The interesting thing which you must remember 36 00:02:04,360 --> 00:02:06,760 is that you must think object. 37 00:02:06,920 --> 00:02:09,720 We ask the collection to do something for us. 38 00:02:09,880 --> 00:02:14,440 The collection browses its own elements by itself. 39 00:02:14,600 --> 00:02:17,240 We provide the processing of each element. 40 00:02:17,400 --> 00:02:20,400 That's where the secret of iterators lies. 41 00:02:21,040 --> 00:02:23,280 This is another example of collect. 42 00:02:23,440 --> 00:02:27,000 This is a collection to which I send the message collect. 43 00:02:27,160 --> 00:02:31,000 In the block, I'll ask every time 44 00:02:31,760 --> 00:02:34,200 whether the element is odd. 45 00:02:34,360 --> 00:02:37,160 I'll aggregate all the results: 46 00:02:37,320 --> 00:02:40,080 false, true, false, true. 47 00:02:43,720 --> 00:02:47,480 Of course, you can write 48 00:02:47,640 --> 00:02:50,400 what you'd usually write in other languages 49 00:02:50,560 --> 00:02:52,680 devoid of blocks and iterators. 50 00:02:52,840 --> 00:02:55,160 You could write: I take the collection, 51 00:02:55,760 --> 00:02:58,680 I build a collection of results. 52 00:02:59,320 --> 00:03:03,560 I'll browse from one to the collection size. 53 00:03:03,720 --> 00:03:04,960 I'll use do. 54 00:03:05,120 --> 00:03:08,920 I browse the collection and add things in the collection result. 55 00:03:09,080 --> 00:03:12,400 You could write all this. It's exactly the same. 56 00:03:12,560 --> 00:03:15,440 It's up to you. Do you want to write something simple 57 00:03:15,600 --> 00:03:19,000 or something complicated? That's the question. 58 00:03:19,160 --> 00:03:22,000 I much prefer the first solution. 59 00:03:24,200 --> 00:03:27,120 In the hierarchy of the Pharo collections, 60 00:03:28,320 --> 00:03:32,000 there's something crucial: all collections are polymorphic 61 00:03:32,160 --> 00:03:35,080 and inherit the class. So you have a common API. 62 00:03:35,240 --> 00:03:39,720 The upside is that the iterators will also work 63 00:03:39,880 --> 00:03:42,840 with most collections. 64 00:03:44,480 --> 00:03:48,080 It's really about thinking object: 65 00:03:48,240 --> 00:03:51,280 you tell the collection to iterate on itself. 66 00:03:51,440 --> 00:03:54,800 We don't know whether we're using a dictionary. 67 00:03:54,960 --> 00:03:58,880 We don't want to know about the internal logic of keys, values, etc. 68 00:03:59,400 --> 00:04:02,320 So you ask the collection to be nice 69 00:04:02,480 --> 00:04:04,960 and to process its elements. 70 00:04:06,640 --> 00:04:11,320 Many iterators can be used to do this. We already saw do: and collect:. 71 00:04:11,480 --> 00:04:14,280 There are more: select:, reject:, detect:, etc. 72 00:04:14,440 --> 00:04:17,840 We'll study a few of these later in this course. 73 00:04:19,320 --> 00:04:22,760 do: is the simplest iterator. 74 00:04:22,920 --> 00:04:26,960 It browses every element of the collection: they're in the transcript. 75 00:04:27,120 --> 00:04:30,560 We already studied it many times. 76 00:04:30,720 --> 00:04:33,320 This is a new iterator: select:. 77 00:04:33,480 --> 00:04:36,560 I want to get all the elements of the collection 78 00:04:36,720 --> 00:04:38,360 which match a criterion. 79 00:04:38,520 --> 00:04:41,960 I want all the odd elements of the collection. 80 00:04:42,120 --> 00:04:45,040 I send select: to the collection. 81 00:04:45,200 --> 00:04:46,440 I pass a block. 82 00:04:46,600 --> 00:04:49,560 Whenever the value of the block is true, 83 00:04:49,720 --> 00:04:53,080 the element concerned is added to the result collection. 84 00:04:55,040 --> 00:04:58,080 It's exactly the same as select: #odd. 85 00:04:58,240 --> 00:05:01,120 When I have a block here 86 00:05:01,280 --> 00:05:05,400 or what amounts to a single message send to the element of the collection, 87 00:05:05,560 --> 00:05:06,920 the block's parameter, 88 00:05:07,080 --> 00:05:10,760 I can display the name of the message to be sent as a symbol. 89 00:05:10,920 --> 00:05:12,480 It's even shorter. 90 00:05:12,640 --> 00:05:16,000 It only works with unary messages. 91 00:05:17,920 --> 00:05:20,880 You may use other types of iterators such as reject:. 92 00:05:21,040 --> 00:05:24,160 I want to get rid of the odd elements of the collection. 93 00:05:24,320 --> 00:05:27,520 In the results, I'll only have even elements left. 94 00:05:28,520 --> 00:05:30,160 Or I want to use detect:. 95 00:05:30,320 --> 00:05:34,000 I want to detect the first element that matches a criterion: 96 00:05:34,160 --> 00:05:37,000 the value of the block must be true. 97 00:05:37,160 --> 00:05:40,920 I want the first odd element of the collection: 11. 98 00:05:42,320 --> 00:05:46,880 Sometimes, you want to detect the first element that matches a criterion. 99 00:05:47,040 --> 00:05:50,120 If there isn't any, you want a default value: 100 00:05:50,280 --> 00:05:52,440 detect: ifNone:. 101 00:05:52,600 --> 00:05:57,360 If there is no match, it will return the value of this block, 102 00:05:57,520 --> 00:05:59,640 which is 0. 103 00:05:59,800 --> 00:06:04,800 There are other iterators which make a programmer's life easier. 104 00:06:04,960 --> 00:06:06,800 For instance, anySatisfy: 105 00:06:06,960 --> 00:06:10,600 tests if one object meets the criterion. 106 00:06:10,760 --> 00:06:13,320 I can test if all objects meet the criterion. 107 00:06:13,480 --> 00:06:17,320 I can browse the collection in reverse, from the end. 108 00:06:17,480 --> 00:06:22,360 I can browse the collection with an index or browse its elements in pairs. 109 00:06:22,520 --> 00:06:26,480 I can browse all the possible circular permutations, etc. 110 00:06:26,640 --> 00:06:28,960 There are many iterators. 111 00:06:29,120 --> 00:06:31,480 You can build new ones, too. 112 00:06:31,640 --> 00:06:35,320 I want to browse one collection 1 2 3 113 00:06:35,480 --> 00:06:38,440 as well as another collection. 114 00:06:38,600 --> 00:06:42,600 In the block do:, I have :x and :y which are two parameters. 115 00:06:42,760 --> 00:06:46,840 :x is an element of the first collection; 116 00:06:47,000 --> 00:06:48,920 y:, of the second. 117 00:06:49,080 --> 00:06:51,080 I can multiply these elements: 118 00:06:51,240 --> 00:06:53,720 the results are 10, 40, and 90. 119 00:06:54,840 --> 00:06:59,440 Of course, with this iterator, the two collections must be of the same length. 120 00:07:01,360 --> 00:07:04,720 There are other ways: 121 00:07:04,880 --> 00:07:08,120 here I use do: separatedBy:. 122 00:07:08,280 --> 00:07:11,280 I have a collection. I browse every element. 123 00:07:11,440 --> 00:07:14,040 Whenever one element is browsed, 124 00:07:14,200 --> 00:07:17,680 I give value to one block which matches a comma. 125 00:07:17,840 --> 00:07:20,480 So I can browse a, 126 00:07:20,640 --> 00:07:23,320 display a comma, then b, then a comma, then c. 127 00:07:23,480 --> 00:07:26,400 Between each element, I perform one action. 128 00:07:28,880 --> 00:07:31,640 This is the iterator groupedBy:. 129 00:07:31,800 --> 00:07:36,040 I can use it to group the elements of a collection 130 00:07:36,200 --> 00:07:37,720 with respect to criteria. 131 00:07:37,880 --> 00:07:42,040 I sent this message to the collection 1 2 3 4 5 6 7. 132 00:07:42,200 --> 00:07:45,480 As a result, I get a dictionary: 133 00:07:47,000 --> 00:07:50,440 all the elements which returned false to this criterion, 134 00:07:50,600 --> 00:07:52,800 which was #even, the even elements. 135 00:07:52,960 --> 00:07:56,000 As you can see, I have all the odd elements. 136 00:07:56,160 --> 00:07:59,520 All the even elements returned true. 137 00:08:02,280 --> 00:08:04,520 It's often the case, when you compute, 138 00:08:04,680 --> 00:08:07,720 that you tend to nest collections in collections. 139 00:08:07,880 --> 00:08:11,440 You end up with huge nesting levels. 140 00:08:11,600 --> 00:08:14,480 This is an example built by hand. 141 00:08:14,640 --> 00:08:17,560 These are collections nested in collections. 142 00:08:17,720 --> 00:08:22,200 We'd like to flatten the collection: to even everything out. 143 00:08:22,880 --> 00:08:26,960 In Pharo, there's an easy way: 144 00:08:27,120 --> 00:08:29,120 the flatCollect: iterator. 145 00:08:29,280 --> 00:08:33,520 I browse the elements and build a new collection where everything is even. 146 00:08:35,240 --> 00:08:38,280 You end up with the 1 2 3 4 5 6 collection. 147 00:08:38,440 --> 00:08:40,600 The nesting levels are all gone. 148 00:08:44,040 --> 00:08:48,520 I don't intend to tell you about every Pharo iterator. 149 00:08:48,680 --> 00:08:52,480 It'd be long and unpleasant. I just want to show there are many. 150 00:08:52,640 --> 00:08:54,280 You can define your own 151 00:08:54,440 --> 00:08:57,760 by reading about collection classes. 152 00:08:57,920 --> 00:08:59,560 Find out about them. 153 00:08:59,720 --> 00:09:02,960 For instance, start with the iterators you already know. 154 00:09:03,120 --> 00:09:05,840 You can wonder how do: is implemented. 155 00:09:06,000 --> 00:09:08,600 I look for it in the hierarchy of collections. 156 00:09:08,760 --> 00:09:13,760 I realize it's implemented as SequenceableCollection. 157 00:09:13,920 --> 00:09:16,680 The method do: selects aBlock as its parameter. 158 00:09:16,840 --> 00:09:19,400 This is the collection's implementation. 159 00:09:19,560 --> 00:09:23,320 1 to: self size do: [i:| aBlock. 160 00:09:23,480 --> 00:09:26,600 I evaluate the block used as the parameter 161 00:09:26,760 --> 00:09:29,840 by passing it the element i. 162 00:09:30,000 --> 00:09:31,160 It's very easy. 163 00:09:31,960 --> 00:09:37,280 In Pharo, iterators are very powerful, as we just saw. 164 00:09:37,440 --> 00:09:41,880 Every collection supports the iterators polymorphically. 165 00:09:42,040 --> 00:09:45,200 Programmers use iterators 166 00:09:45,360 --> 00:09:48,240 which get implemented by collection classes 167 00:09:49,000 --> 00:09:51,720 according to the collection they represent. 168 00:09:52,520 --> 00:09:55,200 You can define new ones. It's very interesting. 169 00:09:55,360 --> 00:09:58,840 I can define my own iterators on the collection classes. 170 00:10:00,480 --> 00:10:04,480 There's a small nuance for those who know the iterator design pattern: 171 00:10:05,160 --> 00:10:10,480 a developer cannot choose when to go to the next element. 172 00:10:10,640 --> 00:10:14,120 The collection decides it internally. 173 00:10:14,280 --> 00:10:17,160 next isn't sent directly to the iterator. 174 00:10:17,320 --> 00:10:20,920 It's a nuance for those who know the Iterator design pattern. 175 00:10:21,520 --> 00:10:25,720 Iterators are very powerful. 176 00:10:25,880 --> 00:10:28,960 They're a programmer's best friends. 177 00:10:29,120 --> 00:10:31,120 It makes writing programs easier: 178 00:10:31,280 --> 00:10:34,280 you can write short, simple, and elegant code. 179 00:10:34,440 --> 00:10:37,320 It ensures 180 00:10:37,960 --> 00:10:40,720 data encapsulation in a collection.