1 00:00:06,732 --> 00:00:07,680 - In the previous lesson, 2 00:00:07,680 --> 00:00:10,110 we looked at a trait called PartialOrd 3 00:00:10,110 --> 00:00:13,590 where you can specify how to compare two values. 4 00:00:13,590 --> 00:00:16,560 It turns out there's another trait called Ord, 5 00:00:16,560 --> 00:00:17,970 which inherits from it. 6 00:00:17,970 --> 00:00:22,410 So PartialOrd is the super trait 7 00:00:22,410 --> 00:00:23,850 and then inheriting from it, 8 00:00:23,850 --> 00:00:26,760 we have the Ord trait like so, 9 00:00:26,760 --> 00:00:30,750 and what the Ord trait gives you on top of partial ordering 10 00:00:30,750 --> 00:00:34,110 is a concept called total ordering, total ordering. 11 00:00:34,110 --> 00:00:36,570 It's quite a tricky mathematical concept. 12 00:00:36,570 --> 00:00:39,120 It's explained to you in the Wiki site if you're interested. 13 00:00:39,120 --> 00:00:40,710 Let's take a look. 14 00:00:40,710 --> 00:00:43,710 This is the Wiki site which explains total ordering 15 00:00:43,710 --> 00:00:46,260 and it does get quite mathematical 16 00:00:46,260 --> 00:00:50,400 if a number type like I don't know, 17 00:00:50,400 --> 00:00:52,110 employee or bank account. 18 00:00:52,110 --> 00:00:54,420 If it implements total ordering, 19 00:00:54,420 --> 00:00:57,400 then it supports all of these kind of equivalences 20 00:00:58,530 --> 00:01:01,200 and then there's more maths down here. 21 00:01:01,200 --> 00:01:04,470 So if your maths is kind of okay, then you can read 22 00:01:04,470 --> 00:01:06,690 through this and it'll be quite interesting. 23 00:01:06,690 --> 00:01:08,670 You don't have to understand all of this detail 24 00:01:08,670 --> 00:01:11,190 in order to use the Ord trait. 25 00:01:11,190 --> 00:01:14,100 It would help, but it's not essential by any means. 26 00:01:14,100 --> 00:01:17,430 So the Ord trait from a Rust point of view, 27 00:01:17,430 --> 00:01:21,300 well, first of all, it does inherit from PartialOrd, okay? 28 00:01:21,300 --> 00:01:24,270 So it'll inherit comparison capabilities 29 00:01:24,270 --> 00:01:26,253 from the PartialOrd trait. 30 00:01:27,540 --> 00:01:30,460 So it'll inherit the partial_comp function 31 00:01:31,500 --> 00:01:34,440 to compare two items to see less than or greater than. 32 00:01:34,440 --> 00:01:38,910 It inherits the less than test from PartialOrd, 33 00:01:38,910 --> 00:01:40,440 less than or equal to, 34 00:01:40,440 --> 00:01:42,750 greater than and greater than or equal to. 35 00:01:42,750 --> 00:01:44,310 So all of those capabilities 36 00:01:44,310 --> 00:01:47,820 are already inherited from PartialOrd. 37 00:01:47,820 --> 00:01:50,970 I guess the question is what extra do we get 38 00:01:50,970 --> 00:01:52,890 when we inherit from Ord? 39 00:01:52,890 --> 00:01:56,403 So the Ord trait specifies these additional methods. 40 00:01:57,510 --> 00:02:01,860 So you you would say I want to implement PartialOrd, 41 00:02:01,860 --> 00:02:05,100 so Ord to compare my type against some other type. 42 00:02:05,100 --> 00:02:07,560 The other type on the right-hand side is assumed 43 00:02:07,560 --> 00:02:08,910 to be the same type as you. 44 00:02:09,780 --> 00:02:10,920 So you'd have two objects 45 00:02:10,920 --> 00:02:13,047 of the same type being compared basically. 46 00:02:13,047 --> 00:02:17,130 And what you do, you have to implement the comp function. 47 00:02:17,130 --> 00:02:19,140 It takes an instance of you 48 00:02:19,140 --> 00:02:20,950 and an instance of the other object 49 00:02:22,020 --> 00:02:23,760 and it returns one of these Ordering enums. 50 00:02:23,760 --> 00:02:25,080 Remember that from before? 51 00:02:25,080 --> 00:02:26,820 The Ordering enum basically indicates 52 00:02:26,820 --> 00:02:29,070 whether you are less than, equal 53 00:02:29,070 --> 00:02:31,440 or greater than the other object. 54 00:02:31,440 --> 00:02:32,910 So you'd implement logic in here 55 00:02:32,910 --> 00:02:35,853 to be doing either less than equal or greater than. 56 00:02:37,110 --> 00:02:37,980 And as well as that, 57 00:02:37,980 --> 00:02:40,500 once you've told it how to compare two values, 58 00:02:40,500 --> 00:02:43,020 the Rust compiler will automatically implement 59 00:02:43,020 --> 00:02:47,520 by default the maximum, minimum and clamp function. 60 00:02:47,520 --> 00:02:50,550 Those functions are implemented by default based 61 00:02:50,550 --> 00:02:53,280 on the algorithm you specify in cmp. 62 00:02:53,280 --> 00:02:56,160 So the way you'd call the max function, for example, 63 00:02:56,160 --> 00:03:01,160 we should say object a.max, object b like so. 64 00:03:02,250 --> 00:03:05,040 The a object gets passed into self 65 00:03:05,040 --> 00:03:06,570 and the b object gets passed in 66 00:03:06,570 --> 00:03:09,510 as the other parameter like that. 67 00:03:09,510 --> 00:03:14,510 And what you do is return an instance of the same type. 68 00:03:14,940 --> 00:03:17,520 So whatever your type is. 69 00:03:17,520 --> 00:03:19,050 Either a or b will get returned. 70 00:03:19,050 --> 00:03:20,820 Either a copy of the value a 71 00:03:20,820 --> 00:03:22,440 or a copy of the value b will be returned, 72 00:03:22,440 --> 00:03:23,733 whichever is the larger. 73 00:03:25,380 --> 00:03:27,030 And the min function obviously works 74 00:03:27,030 --> 00:03:28,380 in a similar kind of way, 75 00:03:28,380 --> 00:03:31,140 except that it returns the minimum of two values. 76 00:03:31,140 --> 00:03:32,520 And then we have this interesting function, 77 00:03:32,520 --> 00:03:33,360 we've got a clamp. 78 00:03:33,360 --> 00:03:34,560 It's an interesting name for it. 79 00:03:34,560 --> 00:03:35,393 And basically what it does, 80 00:03:35,393 --> 00:03:39,180 it bounds a value within a upper and lower bound. 81 00:03:39,180 --> 00:03:42,610 So you could say something like this, you could say a.clamp 82 00:03:43,890 --> 00:03:47,760 and then you give it a max, a minimum value that you'd allow 83 00:03:47,760 --> 00:03:52,760 for a and a maximum value that you'd allow for a like so. 84 00:03:54,180 --> 00:03:56,370 If you passed in, it's like a number range. 85 00:03:56,370 --> 00:04:00,370 You can imagine that minA, minA 86 00:04:02,157 --> 00:04:04,323 and maxA are here. 87 00:04:05,490 --> 00:04:06,960 If you pass in a number for A, 88 00:04:06,960 --> 00:04:09,060 which is kind of between the minimum and maximum, 89 00:04:09,060 --> 00:04:10,980 it'll just return that value. 90 00:04:10,980 --> 00:04:13,410 If you pass in a value smaller than the minimum, 91 00:04:13,410 --> 00:04:15,480 then it'll return the minimum 92 00:04:15,480 --> 00:04:17,820 and if you pass in a value greater than the maximum, 93 00:04:17,820 --> 00:04:18,900 then it'll return the maximum. 94 00:04:18,900 --> 00:04:21,360 So it'll give you back a value which is guaranteed 95 00:04:21,360 --> 00:04:23,430 to be clamped inside that range. 96 00:04:23,430 --> 00:04:24,720 So it's quite an elegant concept 97 00:04:24,720 --> 00:04:27,630 and that's implemented for you automatically 98 00:04:27,630 --> 00:04:29,760 once you've told it how to compare two items. 99 00:04:29,760 --> 00:04:31,460 It can figure that out for itself. 100 00:04:32,520 --> 00:04:35,340 So the easiest way to implement the Ord trait 101 00:04:35,340 --> 00:04:38,777 is automatically via the derive mechanism. 102 00:04:38,777 --> 00:04:40,440 Now, there are some other traits 103 00:04:40,440 --> 00:04:42,030 you've gotta implement as well. 104 00:04:42,030 --> 00:04:43,500 If you implement Ord, 105 00:04:43,500 --> 00:04:47,730 you also have to implement PartialOrd Eq and PartialEq. 106 00:04:47,730 --> 00:04:51,120 And again, in most cases, you'd use automatic derivation 107 00:04:51,120 --> 00:04:54,210 to implement those traits, like I've done here. 108 00:04:54,210 --> 00:04:56,850 I've got a simple structure type, ExamMark 109 00:04:56,850 --> 00:04:58,020 and I want to support 110 00:04:58,020 --> 00:05:01,770 like the minimum, maximum, clamping mechanism for Ord. 111 00:05:01,770 --> 00:05:04,560 I want to support the less than, greater than, 112 00:05:04,560 --> 00:05:05,430 greater than, equal to, 113 00:05:05,430 --> 00:05:07,830 less than or equal to from PartialOrd. 114 00:05:07,830 --> 00:05:10,110 And I want to support comparability 115 00:05:10,110 --> 00:05:13,230 via the equality and partial equality and all of those, 116 00:05:13,230 --> 00:05:16,380 as long as your type here understands comparison, 117 00:05:16,380 --> 00:05:19,200 like ints do, then you can just get the compiler 118 00:05:19,200 --> 00:05:21,090 to generate these capabilities for you, 119 00:05:21,090 --> 00:05:23,670 plus any other traits that you might also want 120 00:05:23,670 --> 00:05:24,993 to implement, like debug. 121 00:05:26,580 --> 00:05:29,880 Right, So let's say I've, on the previous slide, 122 00:05:29,880 --> 00:05:34,880 my ExamMark structure implements the the Ord trait. 123 00:05:35,460 --> 00:05:37,920 Then you can call the min function. 124 00:05:37,920 --> 00:05:39,900 I've created some ExamMarks here. 125 00:05:39,900 --> 00:05:43,326 I can say ExamMark1.min, ExamMark2. 126 00:05:43,326 --> 00:05:47,940 M1 was 90, m2 is 99. 127 00:05:47,940 --> 00:05:49,710 So this will return the smaller, 128 00:05:49,710 --> 00:05:52,063 it'll return an ExamMark set to be 90. 129 00:05:52,950 --> 00:05:54,420 If I call the max function, 130 00:05:54,420 --> 00:05:57,210 it'll return a copy of the larger ExamMark. 131 00:05:57,210 --> 00:05:59,280 That'll be 99. 132 00:05:59,280 --> 00:06:03,210 Clamp, m3 is out of range here. 133 00:06:03,210 --> 00:06:05,610 I want to clamp m3 to be 134 00:06:05,610 --> 00:06:07,680 this is the minimum ExamMark I'm going to allow. 135 00:06:07,680 --> 00:06:09,090 You can't get less than zero 136 00:06:09,090 --> 00:06:11,970 no matter how badly you try in an exam. 137 00:06:11,970 --> 00:06:13,500 And you can't get more than 100. 138 00:06:13,500 --> 00:06:16,890 So the minimum is zero and the maximum value is 100. 139 00:06:16,890 --> 00:06:19,080 If you pass in the value greater than the maximum, 140 00:06:19,080 --> 00:06:22,020 it'll just return the maximum, 100. 141 00:06:22,020 --> 00:06:25,080 If you pass in a value less than the minimum, 142 00:06:25,080 --> 00:06:26,850 then it'll return you back the minimum value. 143 00:06:26,850 --> 00:06:28,710 So the value that you get back would be clamped 144 00:06:28,710 --> 00:06:31,350 to be within the range of zero to 100. 145 00:06:31,350 --> 00:06:33,510 So that's actually quite nice. 146 00:06:33,510 --> 00:06:35,850 Let's see an example in our demo project. 147 00:06:35,850 --> 00:06:38,400 We run the main code and then we'll look at demo_ord 148 00:06:38,400 --> 00:06:39,723 to see this in practice. 149 00:06:40,800 --> 00:06:42,150 Okay, let's go. 150 00:06:42,150 --> 00:06:46,119 Here's my main code and we are right down here now. 151 00:06:46,119 --> 00:06:51,119 Demo_ord, there it is, and here's the code. 152 00:06:51,240 --> 00:06:53,490 I've got a simple structure. 153 00:06:53,490 --> 00:06:54,600 It is really nice. 154 00:06:54,600 --> 00:06:56,580 Once you get into the kind of the ethos of Rust, 155 00:06:56,580 --> 00:06:58,650 you start appreciating its elegance. 156 00:06:58,650 --> 00:07:03,180 The compiler will implement minimum, maximum clamp. 157 00:07:03,180 --> 00:07:06,000 It'll implement the comparability, less than, 158 00:07:06,000 --> 00:07:08,430 equal, less than or equal to, greater than or equal to. 159 00:07:08,430 --> 00:07:10,290 It'll implement equality tests. 160 00:07:10,290 --> 00:07:12,450 Oh, I'm going to allow my structure type 161 00:07:12,450 --> 00:07:14,670 to be copyable and clonable. 162 00:07:14,670 --> 00:07:18,120 Remember, the copy trait inherits from clone. 163 00:07:18,120 --> 00:07:20,070 So if you implement the copy trait 164 00:07:20,070 --> 00:07:21,990 so that the value gets copied, not moved, 165 00:07:21,990 --> 00:07:23,640 you also have to implement clone. 166 00:07:23,640 --> 00:07:25,710 Oh and debug as well, just for good measure. 167 00:07:25,710 --> 00:07:28,927 All of that, no charge, completely free, 168 00:07:28,927 --> 00:07:32,253 "No charge," as one proton said to another neutron. 169 00:07:33,300 --> 00:07:36,613 Anyway, there are my ExamMarks and m1.min m2, 170 00:07:38,760 --> 00:07:41,700 that's courtesy of the Ord trait 171 00:07:41,700 --> 00:07:43,650 and it'll give me back the maximum 172 00:07:43,650 --> 00:07:47,460 and then clamp values between the minimum zero and 100 173 00:07:47,460 --> 00:07:49,560 and the minimum zero and 100 there. 174 00:07:49,560 --> 00:07:53,823 So we just need to run this and have a look at the results. 175 00:08:01,380 --> 00:08:03,510 Okay then, so what are we gonna get? 176 00:08:03,510 --> 00:08:08,420 The minimum of m1 and m2 should be 90 and it is 90. 177 00:08:10,584 --> 00:08:15,584 The maximum of m1 and m2 should be 99 and it is 99. 178 00:08:17,124 --> 00:08:20,850 If m3 is too large, when I clamp it 179 00:08:20,850 --> 00:08:25,320 between the ExamMark zero and the ExamMark 100, 180 00:08:25,320 --> 00:08:29,490 it'll clamp to be 100, inclusive notice. 181 00:08:29,490 --> 00:08:32,820 And if m4 is less than the minimum, 182 00:08:32,820 --> 00:08:35,460 when I clamp it between zero and 100, 183 00:08:35,460 --> 00:08:39,780 it'll gimme the minimum value zero like so. 184 00:08:39,780 --> 00:08:43,530 So very nice indeed. 185 00:08:43,530 --> 00:08:47,100 This automatic derivation mechanism is what you use most 186 00:08:47,100 --> 00:08:49,740 of the time, like I said, because the types, 187 00:08:49,740 --> 00:08:51,300 when you have a numeric type, 188 00:08:51,300 --> 00:08:54,480 the data in here will be something like integer or float 189 00:08:54,480 --> 00:08:57,750 and they already understand these capabilities. 190 00:08:57,750 --> 00:08:59,790 So the compiler's capable of generating all 191 00:08:59,790 --> 00:09:01,500 of this stuff automatically for you 192 00:09:01,500 --> 00:09:03,360 without you having to do any work at all. 193 00:09:03,360 --> 00:09:06,003 You just use the functionality and it works.