1 00:00:06,600 --> 00:00:09,870 - So we just finished the topic on methods, 2 00:00:09,870 --> 00:00:11,160 which teaches us how to-- 3 00:00:11,160 --> 00:00:16,080 or the mechanics behind how you add behavior to data. 4 00:00:16,080 --> 00:00:19,870 And I told you that I want this to be the exception, 5 00:00:19,870 --> 00:00:20,840 not the rule. 6 00:00:20,840 --> 00:00:24,580 But I want to start showing you now the mechanics, 7 00:00:24,580 --> 00:00:26,730 and we'll look at some of the semantics, 8 00:00:26,730 --> 00:00:28,790 of interfaces, okay. 9 00:00:28,790 --> 00:00:33,370 And interfaces give us the ability to have polymorphism. 10 00:00:33,370 --> 00:00:37,200 And there's a saying or a quote from the inventor 11 00:00:37,200 --> 00:00:39,160 of BASIC, Tom Kurtz. 12 00:00:39,160 --> 00:00:43,690 And he describes what polymorphism is perfectly. 13 00:00:43,690 --> 00:00:47,040 Polymorphism means that you write a certain program 14 00:00:47,040 --> 00:00:50,350 and it behaves differently depending upon the data 15 00:00:50,350 --> 00:00:51,690 that it operates on. 16 00:00:51,690 --> 00:00:53,848 I wanna change that up a little bit and just say, 17 00:00:53,848 --> 00:00:58,760 polymorphism means that a piece of code changes its behavior 18 00:00:58,760 --> 00:01:02,720 depending on the concrete data that it is operating on. 19 00:01:02,720 --> 00:01:05,730 This is critical, I keep talking to you about, 20 00:01:05,730 --> 00:01:07,300 concrete data drives everything. 21 00:01:07,300 --> 00:01:09,680 Concrete data and semantics drive everything. 22 00:01:09,680 --> 00:01:11,430 And here it is, we're talking about decoupling, 23 00:01:11,430 --> 00:01:14,380 which is focused on behavior, because what's driving it? 24 00:01:14,380 --> 00:01:15,213 The data. 25 00:01:15,213 --> 00:01:18,620 And so when should a piece of data have behavior? 26 00:01:18,620 --> 00:01:21,900 Well, one good reason, one good practical reason 27 00:01:21,900 --> 00:01:24,650 is when we need to implement polymorphism 28 00:01:24,650 --> 00:01:26,150 and that polymorphism's gonna give us 29 00:01:26,150 --> 00:01:27,820 that levels of decoupling. 30 00:01:27,820 --> 00:01:29,770 So that's when a piece of data should have behavior, 31 00:01:29,770 --> 00:01:32,500 when we need that decoupling and we wanna be able to process 32 00:01:32,500 --> 00:01:34,500 all the different types of concrete data 33 00:01:34,500 --> 00:01:36,630 with a single piece of code. 34 00:01:36,630 --> 00:01:37,463 That's good. 35 00:01:37,463 --> 00:01:40,480 Now, there may be other times when you wanna have 36 00:01:40,480 --> 00:01:43,810 data have behavior, if it's an API that has to be, 37 00:01:43,810 --> 00:01:45,250 what I would say, stateful. 38 00:01:45,250 --> 00:01:48,500 Right, it's gotta maintain sort of state around the API. 39 00:01:48,500 --> 00:01:51,780 But we gotta be very careful about API design 40 00:01:51,780 --> 00:01:52,613 when we do that. 41 00:01:52,613 --> 00:01:55,130 We'll talk about those things as we go forward. 42 00:01:55,130 --> 00:01:58,940 Okay, so what I wanna do is give you an example 43 00:01:58,940 --> 00:02:03,840 of polymorphism in Go and continue to drive the idea 44 00:02:03,840 --> 00:02:06,570 around this idea that concrete data is driving 45 00:02:06,570 --> 00:02:10,230 the polymorphism because the concrete data has behavior. 46 00:02:10,230 --> 00:02:13,040 Now, in this program, we'll start off right out of the box 47 00:02:13,040 --> 00:02:14,400 on line 10. 48 00:02:14,400 --> 00:02:18,550 On line 10, what we have is the reader interface. 49 00:02:18,550 --> 00:02:20,630 Notice that we're using the keyword 'type.' 50 00:02:20,630 --> 00:02:24,070 This type reader is not based on a struct. 51 00:02:24,070 --> 00:02:26,360 It's based on the interface. 52 00:02:26,360 --> 00:02:29,570 Right, it's got one active behavior read, 53 00:02:29,570 --> 00:02:31,670 which takes a slice of bytes, int, error. 54 00:02:31,670 --> 00:02:34,160 But let's go back and look at reader for a second 55 00:02:34,160 --> 00:02:37,810 because this interface type always boggles my mind. 56 00:02:37,810 --> 00:02:39,083 It's a type, right? 57 00:02:39,083 --> 00:02:41,000 That means that I can do this. 58 00:02:41,000 --> 00:02:43,290 I can say var r 59 00:02:43,290 --> 00:02:44,123 reader. 60 00:02:44,123 --> 00:02:47,780 I can do that, I can declare a variable of this reader type. 61 00:02:47,780 --> 00:02:50,980 But what blows my mind is the fact that 62 00:02:50,980 --> 00:02:53,520 an interface type is not real. 63 00:02:53,520 --> 00:02:56,280 We've gotta make this very, very clear throughout. 64 00:02:56,280 --> 00:02:58,800 Interface types are not real. 65 00:02:58,800 --> 00:03:02,590 R is not real, there's nothing concrete 66 00:03:02,590 --> 00:03:03,670 about an interface type. 67 00:03:03,670 --> 00:03:05,350 Struct types, yes, concrete. 68 00:03:05,350 --> 00:03:07,810 That's real data we can manipulate, we can have fun with it. 69 00:03:07,810 --> 00:03:11,010 But interfaces are not real. 70 00:03:11,010 --> 00:03:15,420 They only define a method set of behavior. 71 00:03:15,420 --> 00:03:18,590 They define a contract of behavior. 72 00:03:18,590 --> 00:03:22,670 There's nothing real about an interface, nothing at all. 73 00:03:22,670 --> 00:03:25,420 There's an implementation detail behind r, 74 00:03:25,420 --> 00:03:29,780 but from our programming model, r does not 75 00:03:29,780 --> 00:03:30,630 exist. 76 00:03:30,630 --> 00:03:33,443 It is not real, there's nothing concrete about it. 77 00:03:33,443 --> 00:03:37,440 This is gonna be an important concept for us 78 00:03:37,440 --> 00:03:41,270 to follow through with as we continue to look at this code. 79 00:03:41,270 --> 00:03:44,590 Okay, so I've defined this interface type 80 00:03:44,590 --> 00:03:46,400 as one active behavior read. 81 00:03:46,400 --> 00:03:48,650 And one of things you know we're looking at mechanics 82 00:03:48,650 --> 00:03:50,080 and we'll talk more about this. 83 00:03:50,080 --> 00:03:54,190 It's very important that your interfaces define a behavior. 84 00:03:54,190 --> 00:03:55,660 Verbs, right? 85 00:03:55,660 --> 00:03:58,300 From my perspective, we're reading, we're writing, 86 00:03:58,300 --> 00:04:01,150 we're running, we're printing, right. 87 00:04:01,150 --> 00:04:03,180 Interfaces are about behavior. 88 00:04:03,180 --> 00:04:05,900 I don't wanna see interfaces that describe things. 89 00:04:05,900 --> 00:04:09,350 I don't wanna see an animal interface or a house or a user. 90 00:04:09,350 --> 00:04:11,940 These are not interfaces, those are not behaviors. 91 00:04:11,940 --> 00:04:14,840 Those are things, that's your concrete data. 92 00:04:14,840 --> 00:04:16,720 The more you get away from that 93 00:04:16,720 --> 00:04:19,880 and the more your interfaces describe behavior, 94 00:04:19,880 --> 00:04:22,840 here we've got reader, has one active behavior, read, 95 00:04:22,840 --> 00:04:24,370 this is behavior, 96 00:04:24,370 --> 00:04:27,680 we're gonna be much better off with the decoupling 97 00:04:27,680 --> 00:04:29,400 because again, we're focused on what? 98 00:04:29,400 --> 00:04:30,300 Behavior. 99 00:04:30,300 --> 00:04:31,330 Behavior, that's it. 100 00:04:31,330 --> 00:04:33,230 And we haven't been taught that kind of stuff 101 00:04:33,230 --> 00:04:34,670 in our object-oriented programming world 102 00:04:34,670 --> 00:04:36,270 because we wanna decouple everything. 103 00:04:36,270 --> 00:04:40,200 I'm trying to go back to, let's use our concrete data 104 00:04:40,200 --> 00:04:43,350 'cause that's the problem and let's decouple what we need to 105 00:04:43,350 --> 00:04:44,183 and that's the behavior. 106 00:04:44,183 --> 00:04:46,110 And I wanna keep this philosophy. 107 00:04:46,110 --> 00:04:48,270 I wanna keep these mechanics and semantics 108 00:04:48,270 --> 00:04:50,100 throughout our entire program. 109 00:04:50,100 --> 00:04:52,100 Now, I've got the reader interface. 110 00:04:52,100 --> 00:04:53,120 It's got one active behavior. 111 00:04:53,120 --> 00:04:54,430 Reader takes a slice of bytes, 112 00:04:54,430 --> 00:04:56,290 returns an int and an error. 113 00:04:56,290 --> 00:04:58,440 Okay, but let me ask you another question 114 00:04:58,440 --> 00:05:01,010 before we get going here. 115 00:05:01,010 --> 00:05:05,000 You know, I could have defined read 116 00:05:05,000 --> 00:05:06,350 to look like this. 117 00:05:06,350 --> 00:05:10,240 I could've said, you know what, let's do this instead. 118 00:05:10,240 --> 00:05:13,560 Let's pass in the number of bytes I wanna read 119 00:05:13,560 --> 00:05:16,293 and return that slice of bytes out. 120 00:05:16,293 --> 00:05:20,650 Many of you might argue that this is a simpler API. 121 00:05:20,650 --> 00:05:23,120 But why is this API horrific? 122 00:05:23,120 --> 00:05:25,300 Why is line 13 so 123 00:05:25,300 --> 00:05:28,660 bad of an API design choice in Go? 124 00:05:28,660 --> 00:05:32,340 That's because if we design our code or write our code 125 00:05:32,340 --> 00:05:35,890 like line 13, every time we make a call to read, 126 00:05:35,890 --> 00:05:38,770 we're gonna be allocating on the heap. 127 00:05:38,770 --> 00:05:41,650 Remember, you have a responsibility in API design, 128 00:05:41,650 --> 00:05:44,380 not only to write precise APIs 129 00:05:44,380 --> 00:05:46,690 where you avoid misuse and fraud, 130 00:05:46,690 --> 00:05:49,120 but you also have a responsibility on the impact 131 00:05:49,120 --> 00:05:51,820 your APIs have on the user machine. 132 00:05:51,820 --> 00:05:53,350 There's an impact here. 133 00:05:53,350 --> 00:05:55,410 And this one is allocation. 134 00:05:55,410 --> 00:05:58,100 You might say, Bill, where is the allocation coming from? 135 00:05:58,100 --> 00:06:01,220 Look, you can't implement methods like this inside the type. 136 00:06:01,220 --> 00:06:03,920 I'm just doing this, so I can just write a little code 137 00:06:03,920 --> 00:06:05,840 to show you that if we were implementing it, 138 00:06:05,840 --> 00:06:07,910 where these allocations would come from. 139 00:06:07,910 --> 00:06:11,470 Look, your first allocation would come from the fact that 140 00:06:11,470 --> 00:06:15,060 you are gonna have to make this slice of bytes 141 00:06:15,060 --> 00:06:16,800 here based on 142 00:06:16,800 --> 00:06:17,640 n. 143 00:06:17,640 --> 00:06:19,940 That's going to be an allocation because n, 144 00:06:19,940 --> 00:06:21,190 we don't know what compile time, 145 00:06:21,190 --> 00:06:23,300 what the backing array should be. 146 00:06:23,300 --> 00:06:26,210 Immediate allocation, there's one potential allocation 147 00:06:26,210 --> 00:06:27,720 for this API design. 148 00:06:27,720 --> 00:06:29,490 But you might say, you know what, Bill? 149 00:06:29,490 --> 00:06:32,770 I'm not going to then allow you to pass an n. 150 00:06:32,770 --> 00:06:34,510 I'm gonna make it even simpler. 151 00:06:34,510 --> 00:06:37,590 I'm just gonna say read and I'll hard code that. 152 00:06:37,590 --> 00:06:39,540 Yup, okay, compiler knows what the size 153 00:06:39,540 --> 00:06:40,950 of the backing array is now. 154 00:06:40,950 --> 00:06:43,930 We've gotten rid of that allocation, but guess what? 155 00:06:43,930 --> 00:06:47,380 Eventually, you've gotta return the slice back up. 156 00:06:47,380 --> 00:06:50,180 That's now gonna cause an allocation on the backing array 157 00:06:50,180 --> 00:06:53,030 because you can't have a pointer down the call stack. 158 00:06:53,030 --> 00:06:56,440 Do you see that this API design is not the right choice? 159 00:06:56,440 --> 00:06:58,940 Or we're gonna have an API that's gonna be in a tight loop. 160 00:06:58,940 --> 00:07:02,130 The other API, the one that I've chosen here, 161 00:07:02,130 --> 00:07:05,320 doesn't allocate 'cause we're asking the caller to allocate 162 00:07:05,320 --> 00:07:07,090 the memory and share it down. 163 00:07:07,090 --> 00:07:10,030 See, in Go, you do have a lot of control over 164 00:07:10,030 --> 00:07:12,520 your memory management because you understand 165 00:07:12,520 --> 00:07:15,410 escape analysis and you can drive data down, 166 00:07:15,410 --> 00:07:18,710 which means that the caller can define the slice, 167 00:07:18,710 --> 00:07:21,700 even hard coded size, share it down the call stack, 168 00:07:21,700 --> 00:07:22,970 and there's no allocation. 169 00:07:22,970 --> 00:07:25,580 Okay, great, just wanna keep bringing up where we can 170 00:07:25,580 --> 00:07:27,810 where allocations are gonna be the escape analysis stuff. 171 00:07:27,810 --> 00:07:29,200 This was one of those places. 172 00:07:29,200 --> 00:07:31,960 Now, I've got my reader interface type, there it is. 173 00:07:31,960 --> 00:07:33,050 I can declare variables. 174 00:07:33,050 --> 00:07:36,020 Remember r is not real, interfaces are not real. 175 00:07:36,020 --> 00:07:38,500 Put this into your head, the only real is concrete. 176 00:07:38,500 --> 00:07:41,350 And on line 15, it's exactly what we've done. 177 00:07:41,350 --> 00:07:44,120 I got a concrete type named file. 178 00:07:44,120 --> 00:07:47,260 And this file represents a concrete piece of data, 179 00:07:47,260 --> 00:07:49,710 some sort of file that you might have on a file system, 180 00:07:49,710 --> 00:07:51,160 and I've got just a name in there. 181 00:07:51,160 --> 00:07:53,340 But more importantly, look on line 20. 182 00:07:53,340 --> 00:07:56,170 On line 20, we have declared a method 183 00:07:56,170 --> 00:08:00,710 and this method has the same signature as the interface. 184 00:08:00,710 --> 00:08:03,203 Look at that, read, slice of bytes, int, error. 185 00:08:04,050 --> 00:08:06,400 Now, Go is about convention over configuration. 186 00:08:07,460 --> 00:08:09,940 Listen to every word that I say right now. 187 00:08:09,940 --> 00:08:11,620 Listen to every single word 188 00:08:11,620 --> 00:08:14,780 'cause not a single word here isn't important. 189 00:08:14,780 --> 00:08:18,860 Because of the method declaration on line 20, 190 00:08:18,860 --> 00:08:20,720 I can now say the following. 191 00:08:20,720 --> 00:08:25,720 The concrete type file now implements the reader interface 192 00:08:25,900 --> 00:08:27,950 using value semantics. 193 00:08:27,950 --> 00:08:29,320 Think about everything I just said. 194 00:08:29,320 --> 00:08:30,840 Every word's important. 195 00:08:30,840 --> 00:08:32,950 Because of the-- 196 00:08:32,950 --> 00:08:37,950 Because of line 20, I can now say the concrete type file 197 00:08:38,280 --> 00:08:41,730 now implements the reader interface 198 00:08:41,730 --> 00:08:43,570 using value semantics. 199 00:08:43,570 --> 00:08:46,600 You see Go is about convention over configuration. 200 00:08:46,600 --> 00:08:50,850 We do not configure an interface to the concrete type 201 00:08:50,850 --> 00:08:52,900 like you might see in other languages. 202 00:08:52,900 --> 00:08:55,870 In other languages, you probably have to do 203 00:08:55,870 --> 00:08:57,340 something like this. 204 00:08:57,340 --> 00:08:59,670 This is not Go, this is configuration. 205 00:08:59,670 --> 00:09:01,530 This is going to limit us at the end of the day. 206 00:09:01,530 --> 00:09:04,410 It actually does limit us and cause our software 207 00:09:04,410 --> 00:09:06,480 to have more lines of code. 208 00:09:06,480 --> 00:09:08,110 Go is about less lines of code. 209 00:09:08,110 --> 00:09:09,840 Go is about being more productive. 210 00:09:09,840 --> 00:09:12,210 And because of the static code analysis, 211 00:09:12,210 --> 00:09:14,810 it's gonna give us a lot of benefits as I'm gonna show you 212 00:09:14,810 --> 00:09:17,710 as we move away from mechanics and into design. 213 00:09:17,710 --> 00:09:19,660 So we don't have to do this in Go. 214 00:09:19,660 --> 00:09:22,110 We just have to declare the method 215 00:09:22,110 --> 00:09:23,860 like we're going on line 20. 216 00:09:23,860 --> 00:09:27,150 And the compiler compile time can identify 217 00:09:27,150 --> 00:09:30,100 interface compliance, satisfaction. 218 00:09:30,100 --> 00:09:33,340 Great, so now, the concrete piece of data 219 00:09:33,340 --> 00:09:35,470 associated with the concrete type file. 220 00:09:35,470 --> 00:09:37,100 Notice I'm using the word 'concrete.' 221 00:09:37,100 --> 00:09:38,450 That struct's concrete. 222 00:09:38,450 --> 00:09:42,030 Now, implements the reader interface, 223 00:09:42,030 --> 00:09:43,940 you know, using the value semantics. 224 00:09:43,940 --> 00:09:45,240 Line 20 again. 225 00:09:45,240 --> 00:09:49,530 The concrete type file now implements the reader interface 226 00:09:49,530 --> 00:09:52,120 using value semantics, there we go. 227 00:09:52,120 --> 00:09:54,390 Forget about the implementation, implementation's silly. 228 00:09:54,390 --> 00:09:56,740 We're just pretending to read a file. 229 00:09:56,740 --> 00:09:59,370 Now, look, I have a second concrete type named pipe, 230 00:09:59,370 --> 00:10:02,730 supposed to represent some sort of networking pipe, right. 231 00:10:02,730 --> 00:10:03,990 But look on line 32. 232 00:10:03,990 --> 00:10:07,260 I also have a method named read with the same signature, 233 00:10:07,260 --> 00:10:09,220 right, that's part of the reader interface. 234 00:10:09,220 --> 00:10:11,010 And therefore, since there's only one method 235 00:10:11,010 --> 00:10:12,000 in the reader interface, 236 00:10:12,000 --> 00:10:15,680 we are satisfying the entire method set of the interface. 237 00:10:15,680 --> 00:10:17,780 Now, because of this, because on line 32, 238 00:10:17,780 --> 00:10:21,910 I can now say the following, the concrete type pipe 239 00:10:21,910 --> 00:10:26,450 now implements the reader interface using value semantics. 240 00:10:26,450 --> 00:10:27,510 There we are again. 241 00:10:27,510 --> 00:10:30,970 I have two distinct pieces of data, two concrete types, 242 00:10:30,970 --> 00:10:34,580 both with their unique implementation 243 00:10:34,580 --> 00:10:36,770 of the reader interface. 244 00:10:36,770 --> 00:10:40,070 Brilliant, this is setting us up for polymorphism. 245 00:10:40,070 --> 00:10:41,800 Remember what polymorphism says. 246 00:10:41,800 --> 00:10:44,430 A piece of code changes its behavior depending upon 247 00:10:44,430 --> 00:10:48,260 the data, the concrete data, it is operating on. 248 00:10:48,260 --> 00:10:49,760 Oh god, I love that saying, I love it. 249 00:10:49,760 --> 00:10:52,310 It gives me chills every time I say it 250 00:10:52,310 --> 00:10:55,320 because I really wanna stress this data-oriented design 251 00:10:55,320 --> 00:10:58,070 and focusing on the concrete data and letting it drive 252 00:10:58,070 --> 00:11:02,460 everything we do, even through the decoupling. 253 00:11:02,460 --> 00:11:04,500 Okay, let's look at what I would call 254 00:11:04,500 --> 00:11:06,840 our polymorphic function. 255 00:11:06,840 --> 00:11:09,420 There it is on line 50, it's called retrieve. 256 00:11:09,420 --> 00:11:12,620 This is polymorphic and there's nothing about the concrete. 257 00:11:12,620 --> 00:11:15,650 In fact, you might even be confused for a second. 258 00:11:15,650 --> 00:11:17,090 Look at the parameter. 259 00:11:17,090 --> 00:11:21,660 The parameter in this function seems to say the following. 260 00:11:21,660 --> 00:11:25,380 It says, pass me a value of type reader. 261 00:11:25,380 --> 00:11:26,340 Can you do that please? 262 00:11:26,340 --> 00:11:29,080 I would love a value of type reader. 263 00:11:29,080 --> 00:11:29,913 Guess what? 264 00:11:29,913 --> 00:11:32,030 We already know this is impossible. 265 00:11:32,030 --> 00:11:34,980 There are no such things as values of type reader. 266 00:11:34,980 --> 00:11:37,370 Values of type reader do not exist 267 00:11:37,370 --> 00:11:39,010 because reader is an interface type 268 00:11:39,010 --> 00:11:40,880 and interface types are valueless. 269 00:11:40,880 --> 00:11:42,470 Whoa, what did I just say? 270 00:11:42,470 --> 00:11:43,740 Think about this. 271 00:11:43,740 --> 00:11:45,820 Interface types 272 00:11:45,820 --> 00:11:46,653 are 273 00:11:46,653 --> 00:11:48,360 valueless. 274 00:11:48,360 --> 00:11:51,020 So it is impossible for this polymorphic function 275 00:11:51,020 --> 00:11:54,590 to be asking for a value of type reader because 276 00:11:54,590 --> 00:11:56,690 it doesn't exist. 277 00:11:56,690 --> 00:11:59,630 Well, if it doesn't exist and that's what it's saying, 278 00:11:59,630 --> 00:12:01,100 what is then really saying? 279 00:12:01,100 --> 00:12:04,290 Well, actually, this is what retrieve is saying. 280 00:12:04,290 --> 00:12:08,640 It is saying, please pass me any piece of concrete data, 281 00:12:08,640 --> 00:12:12,110 any value or any pointer, that satisfies, 282 00:12:12,110 --> 00:12:14,860 that contains the behavior of reader, 283 00:12:14,860 --> 00:12:16,510 the full method set of reader. 284 00:12:16,510 --> 00:12:17,630 Think about this again. 285 00:12:17,630 --> 00:12:20,020 Remember we can only pass concrete data 286 00:12:20,020 --> 00:12:22,840 through those program boundaries, through our app. 287 00:12:22,840 --> 00:12:24,230 That's what's real, that's what we manipulate, 288 00:12:24,230 --> 00:12:25,530 that's solving the problem. 289 00:12:25,530 --> 00:12:27,590 So what is this function saying again? 290 00:12:27,590 --> 00:12:31,290 Pass me any piece of concrete data, any value, 291 00:12:31,290 --> 00:12:34,120 any pointer, that satisfies the reader interface 292 00:12:34,120 --> 00:12:37,230 and implements this contract that has the data, 293 00:12:37,230 --> 00:12:38,370 the full 294 00:12:38,370 --> 00:12:41,110 suite of behavior, 295 00:12:41,110 --> 00:12:43,970 method sets, that satisfies the reader. 296 00:12:43,970 --> 00:12:46,100 And don't we have two concrete pieces of data 297 00:12:46,100 --> 00:12:49,130 in this program already, file and pipe, 298 00:12:49,130 --> 00:12:51,730 that have the full method set of reader? 299 00:12:51,730 --> 00:12:52,880 We do. 300 00:12:52,880 --> 00:12:54,500 But this is my polymorphic function 301 00:12:54,500 --> 00:12:57,000 because it knows nothing about the concrete. 302 00:12:57,000 --> 00:12:59,780 It can operate against any piece of concrete data 303 00:12:59,780 --> 00:13:01,750 that implements the read method. 304 00:13:01,750 --> 00:13:05,030 And you can see here that we're gonna be executing 305 00:13:05,030 --> 00:13:07,640 that behavior through the interface. 306 00:13:07,640 --> 00:13:08,480 Okay, you know what, 307 00:13:08,480 --> 00:13:10,315 let's look at the mechanics on the board. 308 00:13:10,315 --> 00:13:12,200 Let's draw all this stuff out, 309 00:13:12,200 --> 00:13:14,270 so you can see this polymorphism in action, 310 00:13:14,270 --> 00:13:17,730 both the semantics side of it and the mechanics. 311 00:13:17,730 --> 00:13:21,320 Okay, so look what we do right here, right there on line... 312 00:13:21,320 --> 00:13:24,010 I gotta turn this around again, line 41. 313 00:13:24,010 --> 00:13:26,290 Look at line 41, okay, brilliant. 314 00:13:26,290 --> 00:13:27,950 What are we doing on line 41? 315 00:13:27,950 --> 00:13:31,280 We are creating a value of type file. 316 00:13:31,280 --> 00:13:33,910 There's f, there's our file value. 317 00:13:33,910 --> 00:13:37,610 I'm also creating a value of type pipe, there it is, p. 318 00:13:37,610 --> 00:13:38,880 I've got these two values. 319 00:13:38,880 --> 00:13:40,960 Remember we're constructing to a variable. 320 00:13:40,960 --> 00:13:42,760 We're gonna use our value semantic construction. 321 00:13:42,760 --> 00:13:44,110 We've done that, great. 322 00:13:44,110 --> 00:13:46,200 But now, look on line 45. 323 00:13:46,200 --> 00:13:49,440 On line 45, we're making a call to retrieve. 324 00:13:49,440 --> 00:13:53,040 Now, I'm always gonna be asking you the same question. 325 00:13:53,040 --> 00:13:58,040 What semantic is at play when we make this function call? 326 00:13:58,050 --> 00:14:01,360 In other words, is the function receiving its own copy 327 00:14:01,360 --> 00:14:02,950 of the data, value semantics? 328 00:14:02,950 --> 00:14:06,650 Or is it being shared the data, pointer semantics? 329 00:14:06,650 --> 00:14:08,430 We look at this and we realize that 330 00:14:08,430 --> 00:14:12,690 this polymorphic function is being given a copy, 331 00:14:12,690 --> 00:14:14,320 its own copy 332 00:14:14,320 --> 00:14:15,510 of the file. 333 00:14:15,510 --> 00:14:20,510 So we're passing a copy of f across this program boundary. 334 00:14:20,770 --> 00:14:23,150 The compiler during compilation knows 335 00:14:23,150 --> 00:14:26,080 that this piece of data implements the reader interface 336 00:14:26,080 --> 00:14:27,600 using value semantics. 337 00:14:27,600 --> 00:14:29,910 You can see that during static code analysis. 338 00:14:29,910 --> 00:14:31,220 Remember retrieve is saying, 339 00:14:31,220 --> 00:14:33,330 pass me any concrete piece of data, 340 00:14:33,330 --> 00:14:37,330 any value or any pointer, that satisfies, implements 341 00:14:37,330 --> 00:14:40,410 the reader interface, has the full suite of behavior. 342 00:14:40,410 --> 00:14:42,080 We know that this does, right. 343 00:14:42,080 --> 00:14:46,390 We know that this piece of data has a read method. 344 00:14:46,390 --> 00:14:48,050 We know it's there. 345 00:14:48,050 --> 00:14:51,690 Brilliant, now, on the other side though, 346 00:14:51,690 --> 00:14:55,190 even though we're giving it this copy, what we have is r. 347 00:14:55,190 --> 00:14:56,350 And r is 348 00:14:56,350 --> 00:14:58,060 an interface 349 00:14:58,060 --> 00:14:59,110 value. 350 00:14:59,110 --> 00:15:01,610 Now, there's only an implementation detail 351 00:15:01,610 --> 00:15:04,490 because from our programming model, r is not real. 352 00:15:04,490 --> 00:15:08,790 It is valueless, there's nothing concrete about it. 353 00:15:08,790 --> 00:15:13,210 But what is r then from an implementation detail? 354 00:15:13,210 --> 00:15:15,620 R is really an interface value, 355 00:15:15,620 --> 00:15:17,170 which makes it a reference type. 356 00:15:17,170 --> 00:15:20,560 And when r is set to its zero value, there it is, 357 00:15:20,560 --> 00:15:22,390 two pointers, nil, nil. 358 00:15:22,390 --> 00:15:25,610 Now, when we pass this concrete piece of data 359 00:15:25,610 --> 00:15:28,530 over the program boundary, the whole idea here 360 00:15:28,530 --> 00:15:32,390 is there's a relationship between interface values 361 00:15:32,390 --> 00:15:33,720 and our concrete data. 362 00:15:33,720 --> 00:15:35,600 And that is one of storage. 363 00:15:35,600 --> 00:15:39,080 We store concrete data inside of interface values 364 00:15:39,080 --> 00:15:41,740 and when we store the data inside of interface value, 365 00:15:41,740 --> 00:15:45,650 that finally makes the interface value concrete. 366 00:15:45,650 --> 00:15:47,600 Everything's always gotta get back to the concrete. 367 00:15:47,600 --> 00:15:50,940 So the interfaces are really valueless. 368 00:15:50,940 --> 00:15:53,320 Through the mechanism of storing, 369 00:15:53,320 --> 00:15:56,090 when we pass this concrete data across the program boundary, 370 00:15:56,090 --> 00:15:58,490 now, we have something that's more concrete. 371 00:15:58,490 --> 00:16:03,220 And it's this second word that we're using for storage. 372 00:16:03,220 --> 00:16:05,630 So look, we made a copy of f, 373 00:16:05,630 --> 00:16:07,960 we're now storing it inside of the interface. 374 00:16:07,960 --> 00:16:10,690 This is giving us our levels of decoupling. 375 00:16:10,690 --> 00:16:13,760 And because we made a copy of f, what does that mean? 376 00:16:13,760 --> 00:16:14,930 It means what? 377 00:16:14,930 --> 00:16:16,880 Allocation, there it is. 378 00:16:16,880 --> 00:16:19,230 Allocation, every time I draw that little red, 379 00:16:19,230 --> 00:16:21,640 I'm showing hey, allocation. 380 00:16:21,640 --> 00:16:23,260 So we got an allocation now. 381 00:16:23,260 --> 00:16:25,480 Brilliant, what about the first word? 382 00:16:25,480 --> 00:16:28,410 Okay, we're gonna get a little technical here. 383 00:16:28,410 --> 00:16:32,730 The first word points to a very special 384 00:16:32,730 --> 00:16:35,890 internal table that we call the iTable. 385 00:16:35,890 --> 00:16:39,710 Now, if you've ever heard of vtables before 386 00:16:39,710 --> 00:16:42,030 in an object-oriented programming language, 387 00:16:42,030 --> 00:16:44,770 then an iTable's very much like the vtable, 388 00:16:44,770 --> 00:16:47,780 but it's an interface, so we replace v with i. 389 00:16:47,780 --> 00:16:51,920 And vtables are just a matrix of function pointers 390 00:16:51,920 --> 00:16:54,070 that allow us to have base class pointers 391 00:16:54,070 --> 00:16:56,820 go into derived class objects behavior. 392 00:16:56,820 --> 00:16:59,330 And the iTable's kind of doing the same thing. 393 00:16:59,330 --> 00:17:03,350 But the first word of the iTable will always describe 394 00:17:03,350 --> 00:17:08,000 the type of value that we're storing inside the interface. 395 00:17:08,000 --> 00:17:10,760 In this case, we've got a value of type file. 396 00:17:10,760 --> 00:17:14,500 The rest of the iTable will be that function pointer. 397 00:17:14,500 --> 00:17:18,100 So this is going to basically point to the 398 00:17:18,100 --> 00:17:21,160 concrete implementation of read for file. 399 00:17:21,160 --> 00:17:24,240 Right, so what's going to happen now 400 00:17:24,240 --> 00:17:26,010 on line 53? 401 00:17:26,010 --> 00:17:29,040 Remember interfaces are giving us a level of decoupling. 402 00:17:29,040 --> 00:17:33,090 So on line 53, when we call read, 403 00:17:33,090 --> 00:17:37,070 when you call read against the interface, 404 00:17:37,070 --> 00:17:39,200 we do an iTable lookup. 405 00:17:39,200 --> 00:17:40,680 Guess what we have here again? 406 00:17:40,680 --> 00:17:41,800 Indirection. 407 00:17:41,800 --> 00:17:45,860 We do an iTable lookup to find out where the implementation 408 00:17:45,860 --> 00:17:49,660 of the actual read is and then we call that implementation 409 00:17:49,660 --> 00:17:51,770 against, in our case, our copy. 410 00:17:51,770 --> 00:17:54,140 And there we have indirection. 411 00:17:54,140 --> 00:17:55,793 Indirection and allocation. 412 00:17:55,793 --> 00:17:58,320 That is what decoupling costs us. 413 00:17:58,320 --> 00:17:59,540 But guess what? 414 00:17:59,540 --> 00:18:01,530 I've got a polymorphic function that can handle 415 00:18:01,530 --> 00:18:03,640 any kind of concrete data. 416 00:18:03,640 --> 00:18:07,280 And remember, retrieve is changing its behavior. 417 00:18:07,280 --> 00:18:10,830 The call on line 53 is changing its behavior 418 00:18:10,830 --> 00:18:13,280 depending on the concrete data it's operating on. 419 00:18:13,280 --> 00:18:16,850 Right now, retrieve is accessing a file system. 420 00:18:16,850 --> 00:18:18,170 How cool is that? 421 00:18:18,170 --> 00:18:20,350 But let's go look at the next thing. 422 00:18:20,350 --> 00:18:23,900 On line 46, now, we call retrieve again. 423 00:18:23,900 --> 00:18:26,590 Again, what semantic is at play? 424 00:18:26,590 --> 00:18:28,460 Value semantics are at play. 425 00:18:28,460 --> 00:18:33,460 Retrieve is gonna receive its own copy, not of f this time, 426 00:18:33,480 --> 00:18:36,600 but it's gonna retrieve its own copy of p. 427 00:18:36,600 --> 00:18:39,360 And we know p also knows how to read. 428 00:18:39,360 --> 00:18:43,450 That means, this time, the iTable doesn't say file here. 429 00:18:43,450 --> 00:18:46,150 It says, no, no, no, I've got a pipe value. 430 00:18:46,150 --> 00:18:49,990 Brilliant, now this time, when I call read against r, 431 00:18:49,990 --> 00:18:53,520 we're gonna call read against our copy of p. 432 00:18:53,520 --> 00:18:56,920 Allocation, but the behavior has changed. 433 00:18:56,920 --> 00:18:59,610 Polymorphism means that a piece of code like retrieve 434 00:18:59,610 --> 00:19:02,500 changes its behavior depending upon the concrete data 435 00:19:02,500 --> 00:19:03,830 it is operating on. 436 00:19:03,830 --> 00:19:07,120 It's still all driven from real concrete data. 437 00:19:07,120 --> 00:19:10,970 This has now made the interface value concrete. 438 00:19:10,970 --> 00:19:11,920 But at the end of the day, 439 00:19:11,920 --> 00:19:13,860 interface values really are valueless. 440 00:19:13,860 --> 00:19:15,050 They're not real. 441 00:19:15,050 --> 00:19:17,670 Only the concrete data is real. 442 00:19:17,670 --> 00:19:20,600 Now moving forward, I don't particularly care about iTables. 443 00:19:20,600 --> 00:19:21,920 It's a little too technical. 444 00:19:21,920 --> 00:19:23,210 I want you to know they're there. 445 00:19:23,210 --> 00:19:24,930 I want you to know that this is a pointer. 446 00:19:24,930 --> 00:19:27,830 But what I'm gonna be doing moving forward 447 00:19:27,830 --> 00:19:31,980 is putting inside of this word, the type of value 448 00:19:31,980 --> 00:19:34,340 that we have stored inside of the interface. 449 00:19:34,340 --> 00:19:35,970 Okay, so I would be saying here 450 00:19:35,970 --> 00:19:38,060 that we have a value of type pipe. 451 00:19:38,060 --> 00:19:40,600 That means we're using value semantics with the interface. 452 00:19:40,600 --> 00:19:41,710 Here's the copy. 453 00:19:41,710 --> 00:19:44,560 And now, when we call read against our-- 454 00:19:44,560 --> 00:19:47,030 we're calling read against our copy, 455 00:19:47,030 --> 00:19:48,760 then the iTable's giving us all that. 456 00:19:48,760 --> 00:19:51,060 So there's no magic going on here. 457 00:19:51,060 --> 00:19:54,520 Now, this is our basic polymorphism in Go. 458 00:19:54,520 --> 00:19:58,220 It's really showing you when a piece of data 459 00:19:58,220 --> 00:20:00,040 should have behavior. 460 00:20:00,040 --> 00:20:00,990 This is one of those cases 461 00:20:00,990 --> 00:20:03,120 when we need to implement polymorphism. 462 00:20:03,120 --> 00:20:05,590 I cannot stress enough though there is a cost 463 00:20:05,590 --> 00:20:07,540 to decoupling here. 464 00:20:07,540 --> 00:20:10,913 And again, it's the indirection and the allocation.