1 00:00:06,630 --> 00:00:07,463 - In this function, 2 00:00:07,463 --> 00:00:11,340 we're going to see how and why to define generic functions. 3 00:00:11,340 --> 00:00:13,818 So first of all, let's see the need for generic functions. 4 00:00:13,818 --> 00:00:15,690 Have a look at this function. 5 00:00:15,690 --> 00:00:20,280 It takes an array slice, an array of 32 bit integers 6 00:00:20,280 --> 00:00:22,500 and it prints out the length of the array, 7 00:00:22,500 --> 00:00:24,420 how many elements it contains 8 00:00:24,420 --> 00:00:27,210 and also prints out the size of each element. 9 00:00:27,210 --> 00:00:29,940 Well, each element is gonna be a 32 bit integer 10 00:00:29,940 --> 00:00:34,080 so it'll tell me the size of each 32 bit integer. 11 00:00:34,080 --> 00:00:36,750 Well, 32 bits, that would be four bytes. 12 00:00:36,750 --> 00:00:40,620 Remember, the standard crate has a mem module 13 00:00:40,620 --> 00:00:42,570 and the mem module, which is like a namespace 14 00:00:42,570 --> 00:00:45,450 has a size of function, which is generic. 15 00:00:45,450 --> 00:00:46,680 You tell it the type, 16 00:00:46,680 --> 00:00:49,350 and it'll tell you the size of that type in bytes, 17 00:00:49,350 --> 00:00:50,910 four bytes. 18 00:00:50,910 --> 00:00:51,743 Okay? 19 00:00:51,743 --> 00:00:52,770 Now have a look at this function. 20 00:00:52,770 --> 00:00:56,283 This one is similar, but this one takes an f64 slice. 21 00:00:57,120 --> 00:00:59,940 But apart from that, it's the same. 22 00:00:59,940 --> 00:01:01,470 The only difference between the functions 23 00:01:01,470 --> 00:01:02,760 is the type involved. 24 00:01:02,760 --> 00:01:05,850 This function deals with f64. 25 00:01:05,850 --> 00:01:08,730 It'll tell me the length of the array in elements 26 00:01:08,730 --> 00:01:10,050 and the size of each element, 27 00:01:10,050 --> 00:01:12,450 each element being an f64. 28 00:01:12,450 --> 00:01:14,670 So if you look at this function 29 00:01:14,670 --> 00:01:15,930 and this one, the only difference 30 00:01:15,930 --> 00:01:19,983 is that it deals with int 32 here and f64 here. 31 00:01:20,850 --> 00:01:23,299 Don't ever define multiple functions 32 00:01:23,299 --> 00:01:26,700 which are identical apart from the type, okay. 33 00:01:26,700 --> 00:01:28,500 Because you'll have duplicate code, 34 00:01:28,500 --> 00:01:30,090 which you have to maintain separately 35 00:01:30,090 --> 00:01:33,540 and eventually they'll drift out of sync. 36 00:01:33,540 --> 00:01:34,950 And it's not exhaustive. 37 00:01:34,950 --> 00:01:37,582 I've written a function to display information 38 00:01:37,582 --> 00:01:40,927 about an array of integers and floats. 39 00:01:40,927 --> 00:01:43,860 But what about an array of bank accounts 40 00:01:43,860 --> 00:01:46,890 or an array of customers? 41 00:01:46,890 --> 00:01:48,630 Okay, you'd have to write a separate function 42 00:01:48,630 --> 00:01:53,630 display array customer, display array employee. 43 00:01:53,970 --> 00:01:57,130 So clearly this approach having separate functions 44 00:01:58,185 --> 00:01:59,580 each type isn't right, is it? 45 00:01:59,580 --> 00:02:02,970 So in that case, we can define a generic function instead. 46 00:02:02,970 --> 00:02:04,110 And obviously the idea is 47 00:02:04,110 --> 00:02:06,780 instead of specifying a specific type, 48 00:02:06,780 --> 00:02:09,090 you use a placeholder type instead. 49 00:02:09,090 --> 00:02:11,250 So this is a generic function. 50 00:02:11,250 --> 00:02:13,950 After the name of the function, you have angle brackets 51 00:02:13,950 --> 00:02:16,230 and then you have some type prompter here. 52 00:02:16,230 --> 00:02:17,520 I've called it T. 53 00:02:17,520 --> 00:02:19,860 Obviously you can call it anything you like. 54 00:02:19,860 --> 00:02:21,840 You can have multiple type prompters as well, 55 00:02:21,840 --> 00:02:26,840 you'd say like T1 comma, T2 comma, T3. 56 00:02:26,850 --> 00:02:30,810 And then the function receives an array slice of Ts. 57 00:02:30,810 --> 00:02:33,750 Obviously the compiler doesn't know what T is. 58 00:02:33,750 --> 00:02:37,080 When you call it, you'll actually specify an array 59 00:02:37,080 --> 00:02:38,460 and at that point it'll know 60 00:02:38,460 --> 00:02:40,230 what type of array you've passed in. 61 00:02:40,230 --> 00:02:43,170 But in general, the algorithm's the same. 62 00:02:43,170 --> 00:02:45,780 Whatever type it is, the code is the same. 63 00:02:45,780 --> 00:02:50,780 We just use T here instead i32 or f64. 64 00:02:51,090 --> 00:02:51,923 Okay? 65 00:02:51,923 --> 00:02:54,060 So the code here is now generic. 66 00:02:54,060 --> 00:02:56,400 It can be cut out and duplicated 67 00:02:56,400 --> 00:02:59,490 for whatever type of T I pass in. 68 00:02:59,490 --> 00:03:04,465 So if you have a generic function, how do you call it? 69 00:03:04,465 --> 00:03:07,680 Okay, so you can call the generic function 70 00:03:07,680 --> 00:03:10,680 explicitly specify the type like so. 71 00:03:10,680 --> 00:03:12,120 I've got an array of integers. 72 00:03:12,120 --> 00:03:14,910 I call it ai, array of integers. 73 00:03:14,910 --> 00:03:17,013 I've got an array of floats, af. 74 00:03:18,180 --> 00:03:21,810 I call my generic function passing in a type parameter. 75 00:03:21,810 --> 00:03:25,470 So T in this case would be i32 76 00:03:25,470 --> 00:03:29,340 and I've given it a reference to an i32 array. 77 00:03:29,340 --> 00:03:31,380 And then I call the function a second time. 78 00:03:31,380 --> 00:03:34,860 And this time I pass in a different type parameter, f64 79 00:03:34,860 --> 00:03:38,310 and I give it an array size of 64 bit floats. 80 00:03:38,310 --> 00:03:42,450 Okay, so you can tell the compiler what type 81 00:03:42,450 --> 00:03:44,970 to substitute T in the function T 82 00:03:44,970 --> 00:03:48,363 is going to be i32 or T is going to be f64. 83 00:03:49,470 --> 00:03:53,700 In most cases, if the parameter you're passing in, 84 00:03:53,700 --> 00:03:56,490 if the type parameter appears in the incoming signature 85 00:03:56,490 --> 00:03:57,540 of the function, 86 00:03:57,540 --> 00:03:59,970 the compiler can look at the parameters you passed in, 87 00:03:59,970 --> 00:04:02,310 and guess what type you mean. 88 00:04:02,310 --> 00:04:04,830 Okay, so I can simplify the calls here 89 00:04:04,830 --> 00:04:05,850 to the way I've called them here 90 00:04:05,850 --> 00:04:08,070 without specifying the type parameter. 91 00:04:08,070 --> 00:04:11,190 The compiler, it knows that it's a generic function 92 00:04:11,190 --> 00:04:12,780 and it knows at the back of its mind 93 00:04:12,780 --> 00:04:15,420 that it has to figure out what type T is. 94 00:04:15,420 --> 00:04:17,040 But the compiler also knows 95 00:04:17,040 --> 00:04:20,280 that the function receives an array of T. 96 00:04:20,280 --> 00:04:23,760 And if it can see the array passed in is int 32 97 00:04:23,760 --> 00:04:27,000 then it'll reverse engineer and assume 98 00:04:27,000 --> 00:04:30,090 that the type T is i32. 99 00:04:30,090 --> 00:04:33,150 And the type T here is f64. 100 00:04:33,150 --> 00:04:38,040 So if the type parameter T appears as one of the parameters 101 00:04:38,040 --> 00:04:39,600 when you pass in a parameter 102 00:04:39,600 --> 00:04:41,520 that will basically tell the compiler 103 00:04:41,520 --> 00:04:44,310 what type T is gonna be for that particular call 104 00:04:44,310 --> 00:04:46,743 i32 and then f64. 105 00:04:47,940 --> 00:04:52,380 This syntax here is clearly more straightforward 106 00:04:52,380 --> 00:04:55,650 on how to explicitly specify the type here. 107 00:04:55,650 --> 00:04:57,930 So this would be the preferred approach. 108 00:04:57,930 --> 00:04:59,850 Right, well, I'm gonna run an example of that. 109 00:04:59,850 --> 00:05:01,590 Lesson13 generics. 110 00:05:01,590 --> 00:05:04,290 We'll run the main code to entry point 111 00:05:04,290 --> 00:05:07,350 for the application and then demo generic functions 112 00:05:07,350 --> 00:05:11,010 will be where all the action lives and then we'll run it. 113 00:05:11,010 --> 00:05:13,800 Okay, so my source code in main. 114 00:05:13,800 --> 00:05:17,220 let's uncomment the code for demo generic functions. 115 00:05:17,220 --> 00:05:18,690 So we can run that. 116 00:05:18,690 --> 00:05:21,630 And here is the module demo generic functions. 117 00:05:21,630 --> 00:05:24,660 And what I've done, as per the slides, 118 00:05:24,660 --> 00:05:26,430 I've got three different functions. 119 00:05:26,430 --> 00:05:28,770 I've got a function which only deals 120 00:05:28,770 --> 00:05:30,633 with 32 bit integers. 121 00:05:31,523 --> 00:05:33,540 Okay, and we've seen that code. 122 00:05:33,540 --> 00:05:35,370 And then I've got a function which only deals 123 00:05:35,370 --> 00:05:39,900 with 64 bit floats or arrays of, and we've seen that code. 124 00:05:39,900 --> 00:05:42,870 And as mentioned, if you look carefully 125 00:05:42,870 --> 00:05:44,370 the only difference between the functions 126 00:05:44,370 --> 00:05:47,250 is the type here and here 127 00:05:47,250 --> 00:05:49,290 compared to the type here and here. 128 00:05:49,290 --> 00:05:50,370 So in reality, 129 00:05:50,370 --> 00:05:53,010 you wouldn't bother defining those two functions. 130 00:05:53,010 --> 00:05:56,280 You would instead define a single generic function 131 00:05:56,280 --> 00:05:59,220 process array where T is a type parameter, 132 00:05:59,220 --> 00:06:01,500 it's an array of some type T. 133 00:06:01,500 --> 00:06:04,320 When the function is called, it'll become apparent. 134 00:06:04,320 --> 00:06:06,059 And at this point here, you know, 135 00:06:06,059 --> 00:06:08,114 it needs to know what type T is gonna be 136 00:06:08,114 --> 00:06:09,693 when you call the function. 137 00:06:10,770 --> 00:06:13,200 So in my code up here 138 00:06:13,200 --> 00:06:16,830 I go through the steps just to be complete. 139 00:06:16,830 --> 00:06:19,710 First of all, I call a function hardcoded 140 00:06:19,710 --> 00:06:24,540 to receive an array of i32s process array ints. 141 00:06:24,540 --> 00:06:25,923 That's the first function. 142 00:06:26,790 --> 00:06:28,770 And then for due diligence 143 00:06:28,770 --> 00:06:30,810 I then call a function that's hardcoded 144 00:06:30,810 --> 00:06:35,400 to receive an array f64, process array floats. 145 00:06:35,400 --> 00:06:36,723 So that's this function. 146 00:06:37,890 --> 00:06:42,890 And then I call my generic function using explicit type int 147 00:06:42,900 --> 00:06:45,330 for i32 and f64. 148 00:06:45,330 --> 00:06:50,190 Notice that I've got an array of i32 and an array of f64. 149 00:06:50,190 --> 00:06:53,850 So I call the generic function using explicit syntax 150 00:06:53,850 --> 00:06:55,290 to show that you can. 151 00:06:55,290 --> 00:06:57,810 And then I call a function using the implicit syntax. 152 00:06:57,810 --> 00:07:01,210 It'll guess that I, sorry, T is i32 there 153 00:07:02,592 --> 00:07:04,983 and it'll guess that T is f64 here. 154 00:07:06,390 --> 00:07:07,533 So we'll just run it. 155 00:07:11,580 --> 00:07:12,413 Cargo run. 156 00:07:16,800 --> 00:07:21,800 Okay, so that's my array of i32 and my array of f64. 157 00:07:22,440 --> 00:07:25,440 There were five elements in my integer array. 158 00:07:25,440 --> 00:07:29,070 And each element was an i32, four bytes in size. 159 00:07:29,070 --> 00:07:32,310 In my floated point array, I only had three elements. 160 00:07:32,310 --> 00:07:34,950 So when I passed in, when I called my demo array floats 161 00:07:34,950 --> 00:07:37,530 there were three elements and each element was a 64 bit 162 00:07:37,530 --> 00:07:41,220 or eight byte float, an f64 in other words. 163 00:07:41,220 --> 00:07:44,160 And then I called my generic functions 164 00:07:44,160 --> 00:07:46,950 to display the array of integers and floats. 165 00:07:46,950 --> 00:07:48,780 And then I called my generic functions again 166 00:07:48,780 --> 00:07:53,340 using implicit type int to show the syntax. 167 00:07:53,340 --> 00:07:56,430 Okay, so in all of this, if this was real code 168 00:07:56,430 --> 00:08:00,398 then I wouldn't bother writing that function. 169 00:08:00,398 --> 00:08:01,231 It's gone. 170 00:08:01,231 --> 00:08:03,720 I wouldn't bother have written that function. 171 00:08:03,720 --> 00:08:04,553 It's gone. 172 00:08:04,553 --> 00:08:07,440 I'd have just had a single function process array. 173 00:08:07,440 --> 00:08:11,190 And then up here, I'm just gonna peel back my demo. 174 00:08:11,190 --> 00:08:14,430 I wouldn't call the process array int function, 175 00:08:14,430 --> 00:08:18,360 I'd call process array and I'd pass in my array like so 176 00:08:18,360 --> 00:08:21,840 and I'd call my generic function process array like that. 177 00:08:21,840 --> 00:08:22,673 Okay. 178 00:08:22,673 --> 00:08:25,140 And then I guess I could just get rid of the other demo code 179 00:08:25,140 --> 00:08:27,120 because that would be sufficient. 180 00:08:27,120 --> 00:08:29,310 Basically create an array of integers. 181 00:08:29,310 --> 00:08:32,910 The compiler knows what type T is going to be, i32. 182 00:08:32,910 --> 00:08:35,280 Create the array of 64 bit floats. 183 00:08:35,280 --> 00:08:38,640 The compiler knows that T in this case is going to be f64. 184 00:08:38,640 --> 00:08:40,049 So quite straightforward. 185 00:08:40,049 --> 00:08:43,120 I guess there are one or two differences. 186 00:08:43,120 --> 00:08:46,860 The way that you specify the generic type when you call it. 187 00:08:46,860 --> 00:08:49,950 Let me just revert all my code just for old times sake. 188 00:08:49,950 --> 00:08:51,990 I think the only thing that you probably wouldn't expect 189 00:08:51,990 --> 00:08:53,580 from a different programming point of view 190 00:08:53,580 --> 00:08:55,803 is when you do pass in the type parameter explicitly 191 00:08:55,803 --> 00:08:58,740 you have to use these colons before the type name. 192 00:08:58,740 --> 00:09:01,200 So other developers from other languages 193 00:09:01,200 --> 00:09:03,109 might be tempted to do that. 194 00:09:03,109 --> 00:09:05,430 That syntax really doesn't work. 195 00:09:05,430 --> 00:09:08,033 Let me just show you the error messages you get back there. 196 00:09:09,690 --> 00:09:11,019 Yes. 197 00:09:11,019 --> 00:09:14,283 So looking at line 14, 198 00:09:16,200 --> 00:09:19,560 on line 14 when it sees the angle brackets there, 199 00:09:19,560 --> 00:09:21,360 it's kind of scratched its head a little bit and said 200 00:09:21,360 --> 00:09:24,540 did you mean colon colon angle brackets? 201 00:09:24,540 --> 00:09:26,430 Yes, I did. 202 00:09:26,430 --> 00:09:29,310 What a good compiler you are. 203 00:09:29,310 --> 00:09:30,780 I need to put the double colons back in. 204 00:09:30,780 --> 00:09:31,980 Okay, and that really is just something 205 00:09:31,980 --> 00:09:34,913 you need to watch out for when you're getting used to Rust.