1 00:00:06,540 --> 00:00:09,660 - So, type as context, now, applies when 2 00:00:09,660 --> 00:00:12,040 we're gonna need our own custom error type. 3 00:00:12,040 --> 00:00:14,110 I mean, think of networking issues, right? 4 00:00:14,110 --> 00:00:15,890 I mean, how many problems can happen on the network? 5 00:00:15,890 --> 00:00:17,640 Just one, right? 6 00:00:17,640 --> 00:00:18,690 We all wish. 7 00:00:18,690 --> 00:00:20,700 There's tons of things that happen on a network, 8 00:00:20,700 --> 00:00:22,790 so an error variable isn't gonna be enough 9 00:00:22,790 --> 00:00:24,410 to say there was a network issue. 10 00:00:24,410 --> 00:00:27,100 We're gonna need to know what was that network issue? 11 00:00:27,100 --> 00:00:29,730 And the more detail we can get about the network issue, 12 00:00:29,730 --> 00:00:30,940 the more we'll get to know whether 13 00:00:30,940 --> 00:00:32,790 we can recover from it or not. 14 00:00:32,790 --> 00:00:35,000 So, type as context becomes very important 15 00:00:35,000 --> 00:00:37,170 when we start dealing with custom error types. 16 00:00:37,170 --> 00:00:39,850 Now, what I wanna show you are two custom error types 17 00:00:39,850 --> 00:00:42,080 from the JSON package. 18 00:00:42,080 --> 00:00:44,900 This one is called Unmarshal Type Error. 19 00:00:44,900 --> 00:00:46,500 Notice it's an unexported type 20 00:00:46,500 --> 00:00:49,850 with two exported fields, value and type. 21 00:00:49,850 --> 00:00:52,070 I want you to notice on line 22, as well, 22 00:00:52,070 --> 00:00:54,322 that we've implemented, or at least the standard library's 23 00:00:54,322 --> 00:00:59,050 implemented the error interface, using pointer semantics. 24 00:00:59,050 --> 00:01:01,260 Again, pointer semantics are going to be the 25 00:01:01,260 --> 00:01:03,437 default, there will be exception to e's value. 26 00:01:03,437 --> 00:01:05,420 I'm gonna come back and show you that. 27 00:01:05,420 --> 00:01:06,880 Also, look at the implementation 28 00:01:06,880 --> 00:01:08,690 of the error interface, here. 29 00:01:08,690 --> 00:01:12,220 Remember that the implementation is for logging, right? 30 00:01:12,220 --> 00:01:15,340 It allows the concrete value to be an error value, 31 00:01:15,340 --> 00:01:17,300 but it also is for logging. 32 00:01:17,300 --> 00:01:19,550 And one of the things I want you to always look for 33 00:01:19,550 --> 00:01:22,910 is if every field in the custom error type 34 00:01:22,910 --> 00:01:25,460 is being used in the logging message. 35 00:01:25,460 --> 00:01:28,510 If we're missing a field from the logging message, 36 00:01:28,510 --> 00:01:31,940 I would question the relevance of that field. 37 00:01:31,940 --> 00:01:33,690 You wanted to create a custom error type, 38 00:01:33,690 --> 00:01:34,950 you added this field 'cause you thought 39 00:01:34,950 --> 00:01:36,730 it was gonna help the user, but it wasn't enough 40 00:01:36,730 --> 00:01:38,810 to log information about it? 41 00:01:38,810 --> 00:01:41,510 Ehhhh, you know, that could be a smell. 42 00:01:41,510 --> 00:01:44,200 So, we're gonna get an error of this type, 43 00:01:44,200 --> 00:01:47,180 when you don't pass a pointer into an Unmarshal call, 44 00:01:47,180 --> 00:01:50,220 because Unmarshalling and decoding requires, 45 00:01:50,220 --> 00:01:53,160 you know, pointer semantics, shared access. 46 00:01:53,160 --> 00:01:55,320 This custom error type is used when we have 47 00:01:55,320 --> 00:01:57,650 an Unmarshalling error in the JSON package. 48 00:01:57,650 --> 00:01:59,787 That's when you have a document that says, 49 00:01:59,787 --> 00:02:01,870 "This field is a string, but you defined it as 50 00:02:01,870 --> 00:02:05,550 an integer in your, you know, your concrete type." 51 00:02:05,550 --> 00:02:07,840 Then we're gonna get the Unmarshal type error. 52 00:02:07,840 --> 00:02:09,310 That's what this error is for, right? 53 00:02:09,310 --> 00:02:11,160 That's why we have value and type, 54 00:02:11,160 --> 00:02:13,910 but here's the second custom error type 55 00:02:13,910 --> 00:02:15,470 that we have in the JSON package. 56 00:02:15,470 --> 00:02:17,503 It's called Invalid Unmarshal Error. 57 00:02:17,503 --> 00:02:20,210 Look at this, when you don't pass the address 58 00:02:20,210 --> 00:02:22,930 of something into the Unmarshal call. 59 00:02:22,930 --> 00:02:24,790 Again, I want you to notice that we're using 60 00:02:24,790 --> 00:02:27,840 pointer semantics, here, for the implementation, 61 00:02:27,840 --> 00:02:30,040 and I want you to notice that the 62 00:02:30,040 --> 00:02:32,980 message coming out's a little bit more complex. 63 00:02:32,980 --> 00:02:37,470 Okay, we've got these two user-defined, right, 64 00:02:37,470 --> 00:02:38,840 custom error types, part of 65 00:02:38,840 --> 00:02:41,890 the standard library's JSON package. 66 00:02:41,890 --> 00:02:45,750 And I want to show you this function called Unmarshal. 67 00:02:45,750 --> 00:02:48,980 I've taken a snippet of code from the JSON package 68 00:02:48,980 --> 00:02:50,460 for the Unmarshal call. 69 00:02:50,460 --> 00:02:53,590 The one thing I wanna show you here is the second parameter. 70 00:02:53,590 --> 00:02:57,470 The second parameter's based on the empty interface. 71 00:02:57,470 --> 00:03:00,130 The empty interface tells us nothing, 72 00:03:00,130 --> 00:03:02,980 because any piece of data, any value or pointer, 73 00:03:02,980 --> 00:03:06,700 satisfies it, because it doesn't have to have any behavior. 74 00:03:06,700 --> 00:03:07,880 I want to be very careful 75 00:03:07,880 --> 00:03:09,340 when we're using the empty interface. 76 00:03:09,340 --> 00:03:13,250 Don't use it to write generic APIs. 77 00:03:13,250 --> 00:03:15,250 We should be using the empty interface 78 00:03:15,250 --> 00:03:18,060 when we have to pass data around, 79 00:03:18,060 --> 00:03:21,000 where that data can be hidden without problems, 80 00:03:21,000 --> 00:03:23,900 or in this case, where we're gonna use the reflect package, 81 00:03:23,900 --> 00:03:26,310 because what we wanna do is at Runtime, 82 00:03:26,310 --> 00:03:29,040 or dynamically inspect the concrete data. 83 00:03:29,040 --> 00:03:31,550 This is great if you wanna do model validation. 84 00:03:31,550 --> 00:03:33,810 Reflect packages are fantastic for, like, 85 00:03:33,810 --> 00:03:36,160 model validation, or like what we're doing here 86 00:03:36,160 --> 00:03:37,940 with some unmarshalling. 87 00:03:37,940 --> 00:03:38,870 Now, if you notice, we're using 88 00:03:38,870 --> 00:03:41,690 the reflect package, ValueOf function call. 89 00:03:41,690 --> 00:03:43,680 This is how we always start a reflection, 90 00:03:43,680 --> 00:03:45,350 and we're basically saying, 91 00:03:45,350 --> 00:03:48,770 is the concrete data inside of V? 92 00:03:48,770 --> 00:03:51,300 Is it a pointer, and is it nil? 93 00:03:51,300 --> 00:03:53,240 Really, we're saying, if it's not a pointer, 94 00:03:53,240 --> 00:03:55,870 or it's nil, then we're gonna return 95 00:03:55,870 --> 00:03:57,670 this error value, right here. 96 00:03:57,670 --> 00:03:59,130 Again, we've implemented the interface 97 00:03:59,130 --> 00:04:01,610 with pointer semantics we always have to share. 98 00:04:01,610 --> 00:04:03,860 So, we're gonna either store an invalid 99 00:04:03,860 --> 00:04:07,940 unmarshal error pointer in the error interface value, 100 00:04:07,940 --> 00:04:11,570 or we're going to share this unmarshal type error 101 00:04:11,570 --> 00:04:14,410 inside the error interface value. 102 00:04:14,410 --> 00:04:15,980 Okay, and we're going to be processing from 103 00:04:15,980 --> 00:04:18,070 a decoupled state v interface, 104 00:04:18,070 --> 00:04:20,910 but now the question is, what we wanna know is, 105 00:04:20,910 --> 00:04:23,140 what type of value is stored? 106 00:04:23,140 --> 00:04:23,973 What type? 107 00:04:23,973 --> 00:04:25,320 Type is context. 108 00:04:25,320 --> 00:04:29,170 Was it a pointer to this type or a pointer to this type? 109 00:04:29,170 --> 00:04:32,290 Now, Go gives us a speckle, special, that's funny. 110 00:04:32,290 --> 00:04:36,350 Special mechanism to do this type as context, 111 00:04:36,350 --> 00:04:38,140 and it happens on the switch. 112 00:04:38,140 --> 00:04:39,340 So look at what we do. 113 00:04:39,340 --> 00:04:43,270 We call unmarshal, we get back the error interface value, 114 00:04:43,270 --> 00:04:46,240 we ask, is there a concrete type stored inside 115 00:04:46,240 --> 00:04:47,590 the error interface value? 116 00:04:47,590 --> 00:04:48,970 Oh, there is? 117 00:04:48,970 --> 00:04:53,190 Then we do a type assertion on the switch. 118 00:04:53,190 --> 00:04:56,200 Notice that the type assertion is using the keyword "type". 119 00:04:56,200 --> 00:04:58,330 It is the only place where we could do 120 00:04:58,330 --> 00:05:01,420 a type assertion on the keyword "type", inside of a switch. 121 00:05:01,420 --> 00:05:03,900 And what this is letting us do is type as context. 122 00:05:03,900 --> 00:05:07,910 What it's saying is, okay, type assert, 123 00:05:07,910 --> 00:05:11,840 what is inside of the error interface value? 124 00:05:11,840 --> 00:05:16,320 And if it happens to be a pointer of this concrete type, 125 00:05:16,320 --> 00:05:18,710 then let's execute this code, 126 00:05:18,710 --> 00:05:21,290 and e will be a copy of that, right? 127 00:05:21,290 --> 00:05:22,677 There's always going to be a copy on the type assertion, 128 00:05:22,677 --> 00:05:24,370 the copy of the pointer. 129 00:05:24,370 --> 00:05:28,050 Or, if e is a pointer of this type, 130 00:05:28,050 --> 00:05:29,320 then that's what we have. 131 00:05:29,320 --> 00:05:32,780 Let's execute this case and e will be that. 132 00:05:32,780 --> 00:05:35,521 Type as context, it's really cool, right? 133 00:05:35,521 --> 00:05:37,900 The conditional logic is based on 134 00:05:37,900 --> 00:05:40,000 what type of value is stored, 135 00:05:40,000 --> 00:05:41,420 and thanks to the type assertion, 136 00:05:41,420 --> 00:05:43,060 we get a copy of what was stored, 137 00:05:43,060 --> 00:05:45,470 and now we can process our error handling 138 00:05:45,470 --> 00:05:48,080 from that, you know, concrete place. 139 00:05:48,080 --> 00:05:49,830 But, for me, that is also a problem. 140 00:05:49,830 --> 00:05:53,290 We wanna maintain, to the extent we can, 141 00:05:53,290 --> 00:05:55,640 error handling from a decoupled state, 142 00:05:55,640 --> 00:05:57,790 because once we switch from the decoupled state 143 00:05:57,790 --> 00:06:00,730 to the concrete, then any improvements we make 144 00:06:00,730 --> 00:06:03,100 to error handling against those concrete types, 145 00:06:03,100 --> 00:06:05,450 could cause a cascading effect of change 146 00:06:05,450 --> 00:06:06,730 throughout our program. 147 00:06:06,730 --> 00:06:09,390 So, even though this is super cool, right? 148 00:06:09,390 --> 00:06:11,737 This idea of type as context for error handling, 149 00:06:11,737 --> 00:06:15,770 it's kind of dangerous, because we're setting ourselves up 150 00:06:15,770 --> 00:06:18,288 for some potential cascading changes, 151 00:06:18,288 --> 00:06:19,990 throughout the code base. 152 00:06:19,990 --> 00:06:23,570 But type as context can be very powerful 153 00:06:23,570 --> 00:06:25,480 when you need to move concrete data 154 00:06:25,480 --> 00:06:29,050 across program boundaries, where both sides 155 00:06:29,050 --> 00:06:31,810 need to work with the concrete data, itself. 156 00:06:31,810 --> 00:06:34,380 Then this idea of type as context can come in 157 00:06:34,380 --> 00:06:38,170 really, really handy to move data across program boundaries, 158 00:06:38,170 --> 00:06:40,170 maintaining levels of decoupling. 159 00:06:40,170 --> 00:06:42,463 I'm just afraid, when we're using it here, 160 00:06:43,370 --> 00:06:45,890 with error handling, 'cause I'd really rather 161 00:06:45,890 --> 00:06:48,660 be processing the error interface value directly, 162 00:06:48,660 --> 00:06:51,380 or at least maintain levels of decoupling. 163 00:06:51,380 --> 00:06:54,680 So then, how can we maintain this idea 164 00:06:54,680 --> 00:06:58,140 of custom error types without moving into the concrete? 165 00:06:58,140 --> 00:07:00,260 This is where we're gonna start talking about 166 00:07:00,260 --> 00:07:03,853 this idea of behavior as context.