WEBVTT 0 00:02.210 --> 00:03.310 Welcome back. 1 00:03.350 --> 00:09.710 In this lecture you're going to learn what happens when you pass an ordinary value like an integer, a slice 2 00:09.770 --> 00:11.570 or a map to a function. 3 00:11.570 --> 00:14.690 First of all let's take a look at the design diagram again. 4 00:14.930 --> 00:21.570 You have finished half of the job. As you can see updating the results is a unique responsibility. 5 00:21.650 --> 00:23.530 It's a job on its own. 6 00:23.540 --> 00:29.380 So in this lecture you're going to move the update logic to a new function. 7 00:29.410 --> 00:33.960 OK let's take a look at the main function. Here is the update logic. 8 00:34.060 --> 00:39.270 It saves the unique domains to a slice and it increases the visits per domain. 9 00:39.340 --> 00:42.270 And it also keeps track of the total visits. 10 00:42.520 --> 00:44.860 So it updates the parser in the loop. 11 00:45.670 --> 00:47.680 So right above the update logic, 12 00:47.680 --> 00:50.110 I'm going to call a function instead. 13 00:50.170 --> 00:56.050 Now I'm going to send the parser and the parsed result to the function. You'll see in a second, 14 00:56.320 --> 00:57.800 why the function needs them. 15 00:58.390 --> 01:01.650 OK, I'm going to cut the updating logic from here. 16 01:02.760 --> 01:09.650 Inside the parser, I'm going to declare the update function and I'm going to paste the code here. 17 01:09.670 --> 01:14.260 You know that the function needs to take parser and parsed values. 18 01:14.800 --> 01:21.580 So I'm going to declare their types as input parameters like so. As you can see, the update function gets 19 01:21.580 --> 01:29.130 a parser value and it uses the parsing result to update the parser. 20 01:29.130 --> 01:30.060 Oops! It doesn't work. 21 01:30.060 --> 01:32.610 Let's find out the problem. 22 01:32.610 --> 01:39.650 Remember when a struct value is assigned or passed to a function, it gets copied. Here, 23 01:39.690 --> 01:41.860 the parser value is a copy. 24 01:42.060 --> 01:48.060 It is not the original parser value of the main function. To understand the problem better, 25 01:48.060 --> 01:52.810 let's dump the parser value right before calling the update function like so. 26 01:53.370 --> 01:59.190 I'm also going to dump it after the function call. So you can see what changes in the original parser 27 01:59.190 --> 02:01.890 value. And inside the update function, 28 02:01.890 --> 02:09.470 I'm going to put another one as the last statement, so you can see what changes in the local parser value. 29 02:09.660 --> 02:10.780 Let's open the log.txt file. 30 02:10.790 --> 02:18.720 And leave only a single line here. So I can easily debug it. The parser value is zero in 31 02:18.720 --> 02:20.580 the main function. Next, 32 02:20.640 --> 02:23.650 it sends the value to the update function. 33 02:23.730 --> 02:26.850 So the update function updates its local copy. 34 02:27.420 --> 02:34.710 Lastly, the update function returns. For the main function, the domains and total fields don't change. Only 35 02:34.710 --> 02:36.690 the sum field changes. 36 02:36.870 --> 02:40.650 Let's investigate this problem further. 37 02:40.670 --> 02:43.500 Here is the parser value of the main function. 38 02:43.610 --> 02:47.040 As you can see, it starts with zero fields. 39 02:47.060 --> 02:48.440 Here is the update function. 40 02:48.440 --> 02:51.650 It accepts the parser and result values. 41 02:51.710 --> 02:56.510 The main function sends its own parser value to the update function. 42 02:56.570 --> 03:00.110 So the update function receives the parser value. 43 03:00.110 --> 03:02.470 However this value is a copy. 44 03:02.660 --> 03:05.390 So it's not the original parser value. 45 03:05.390 --> 03:09.130 Remember every value in Go gets copied. 46 03:09.290 --> 03:13.560 Go is a 100 percent pass by value language. 47 03:13.580 --> 03:20.330 That's why the update function receives a copy. The update function changes the copy using the result 48 03:20.360 --> 03:29.270 like so. It adds the result to the sum field. It adds a domain name to domains fields, also updates the 49 03:29.270 --> 03:30.370 total field. 50 03:30.620 --> 03:39.430 So when the update function is about to return, this is what the parser value looks like. But the main 51 03:39.430 --> 03:46.540 function never sees the changes because the update function only changes its local parser copy. For 52 03:46.540 --> 03:49.260 the main function, only the sum field changes. 53 03:49.270 --> 03:49.950 But why? 54 03:50.590 --> 03:56.290 Let's talk about how this works behind the scenes. By the way, to better understand what I'm going to 55 03:56.290 --> 03:57.000 explain, 56 03:57.010 --> 04:02.640 you should have watched the slices and map internals lectures. 57 04:02.700 --> 04:05.630 Remember, there are two parser struct values. 58 04:05.640 --> 04:10.140 One is in the main function and the other one is in the update function. 59 04:10.140 --> 04:12.900 Let's take a look at the main function's parser value first. 60 04:12.900 --> 04:16.400 Here is the sums map field. 61 04:16.460 --> 04:17.510 Remember a map 62 04:17.510 --> 04:21.620 value is a pointer. So it stores a memory location. 63 04:21.650 --> 04:24.930 Here it points to the memory address 40. 64 04:25.070 --> 04:27.040 Let's see what it points to. 65 04:27.080 --> 04:34.970 As you can see, it points to a map header. A map header does some magic and lets us work with key value 66 04:34.970 --> 04:36.150 pairs like so. 67 04:36.960 --> 04:40.350 So under the hood, a map value is just a proxy. 68 04:40.400 --> 04:44.120 And it points to the memory location of a real map. 69 04:44.120 --> 04:50.570 Now let's take a look at the update function's parser value. As you can see, it points to the same memory 70 04:50.570 --> 04:51.480 location. 71 04:51.640 --> 04:56.310 It's because it's been copied from the main function's map value. 72 04:56.630 --> 05:00.980 So, both of the map values point to the same memory location. 73 05:01.670 --> 05:09.320 So in summary, when you copy a map value, it will continue to point to the same memory location. 74 05:09.320 --> 05:15.080 There are two different map values but the main and the update functions behind the scenes point to the same 75 05:15.080 --> 05:15.460 map header. 76 05:15.470 --> 05:16.500 map header. 77 05:16.600 --> 05:19.730 That's why the main function can see the updated map. 78 05:22.740 --> 05:27.510 However, the main function cannot see the changes to the other fields (of the parser struct value). 79 05:27.530 --> 05:28.500 Let's see why. 80 05:29.090 --> 05:32.120 Let's first take a look at the original parser value. 81 05:32.120 --> 05:38.870 This is the domains field. As you can see, it doesn't point to a backing array because it's a nil slice. 82 05:38.990 --> 05:42.230 So the length and capacity fields are zero. 83 05:42.260 --> 05:46.600 Now let's take a look at the update function's parser value. As you can see, 84 05:46.640 --> 05:53.600 This time, the domain field points to a memory location. The value of length and capacity fields is 85 05:53.600 --> 05:57.230 1. It's because there is a single element in the backing array. 86 05:57.710 --> 06:01.440 But why doesn't the main function see the new element? 87 06:01.880 --> 06:09.140 It's because the update function can only change its local slice header. However, it never returns that slice 88 06:09.140 --> 06:11.250 header to the main function. 89 06:11.270 --> 06:19.370 That is why the main function cannot see the new element. All it sees is a struct header with zero fields. 90 06:20.060 --> 06:24.110 So in summary, when you change a slice value in a function, 91 06:24.110 --> 06:25.780 you need to return it. 92 06:26.030 --> 06:30.740 So the calling function can see the changes to the slice header. 93 06:30.940 --> 06:32.990 Okay let's get back to the code now. 94 06:36.990 --> 06:39.060 So what is the solution? 95 06:39.120 --> 06:45.090 One of the solutions is returning the copy from the update function like so. 96 06:45.110 --> 06:47.850 I also need to declare a result type. 97 06:47.870 --> 06:50.850 Now let's get back to the main function here. 98 06:50.870 --> 06:56.170 I'm going to override the original P variable with the returned copy like this. 99 06:58.550 --> 07:01.510 As you can see now it works. Before the call, 100 07:01.520 --> 07:03.160 the parser was 0. 101 07:03.410 --> 07:10.060 Here the update function updates its local copy and it returns the updated copy. 102 07:10.070 --> 07:15.580 So the main function receives the copy and updates its own copy. 103 07:15.590 --> 07:18.720 There are three copies of the parser value here. 104 07:18.740 --> 07:20.340 This is the first copy. 105 07:20.390 --> 07:22.010 This is the second copy. 106 07:22.010 --> 07:23.620 This is the last copy. 107 07:23.870 --> 07:31.970 The last one is also a copy because when you return a value it gets copied too. OK, let me remove the 108 07:31.970 --> 07:32.980 debugging calls. 109 07:33.440 --> 07:38.870 Let me also put the records back to the log file. 110 07:38.870 --> 07:41.730 OK, it works, awesome. 111 07:41.750 --> 07:48.380 Now you know how to create functions and how to use them to split a program into functions. 112 07:48.380 --> 07:52.360 You have also learned about the pass by value semantics. 113 07:52.610 --> 07:56.570 In the next section, you're going to learn how to work with pointers. 114 07:56.570 --> 07:57.370 See you there. 115 07:57.470 --> 07:57.710 Bye!