1 00:00:00,000 --> 00:00:04,800 In this section, I want to talk a little bit about idiomatic. Go, if you've 2 00:00:04,800 --> 00:00:08,800 looked at go programs you will have noticed that they all look very similar. 3 00:00:08,800 --> 00:00:12,900 And there are a couple of reasons for this. I think one of them is of course 4 00:00:12,900 --> 00:00:16,700 to go format tool, which forces a certain coding 5 00:00:16,700 --> 00:00:20,200 style, which of course, is actually based on the language itself, which has certain restrictions. 6 00:00:20,200 --> 00:00:24,700 And the other one is that the language is fairly small. It has a fairly 7 00:00:24,700 --> 00:00:28,800 small number of keywords, for example, and that people are quickly, learn the 8 00:00:28,800 --> 00:00:29,600 entire language. 9 00:00:30,000 --> 00:00:34,800 's. And on top of that, there is a certain idiomatic go, which you'll see in 10 00:00:34,800 --> 00:00:38,200 the packages, particularly in the standard packages and written by other people. 11 00:00:38,600 --> 00:00:42,600 Obviously some of that is enforced by go format but some of it is also up to the 12 00:00:42,600 --> 00:00:46,500 programmer and I think it's useful to talk about a few things you'll see 13 00:00:46,500 --> 00:00:48,300 in well-written go. 14 00:00:49,300 --> 00:00:53,300 One particular thing you'll see is an attempt to keep the main flow of 15 00:00:53,300 --> 00:00:57,800 code at the lowest level of indentation. Sometimes, 16 00:00:57,800 --> 00:01:01,700 that doesn't happen and it can make code very different difficult to read. For 17 00:01:01,700 --> 00:01:05,800 example, let's look at something which is going to run 18 00:01:05,800 --> 00:01:09,800 through a sequence of do something and then otherwise get an error. 19 00:01:09,800 --> 00:01:13,700 So it's not uncommon to see. People do something like this, 20 00:01:14,000 --> 00:01:16,200 let's suppose. We're going to open the file. So let's just look at it. 21 00:01:18,000 --> 00:01:22,600 This guy's we're going to open up a file and it returns a file and an error. So we're going to do something like 22 00:01:23,200 --> 00:01:26,100 there's we're going to say OS dot open. 23 00:01:29,100 --> 00:01:33,900 Some file. And if 24 00:01:33,900 --> 00:01:35,300 if everything's alright. 25 00:01:36,500 --> 00:01:40,300 Then well actually often you'll do this if everything's gone wrong then 26 00:01:41,000 --> 00:01:45,800 we're done. Otherwise everything is all right. And then we're going to start doing something with f. So we 27 00:01:45,800 --> 00:01:46,600 might say 28 00:01:48,300 --> 00:01:52,800 So have a look at what we're going to do. For example, we might go through and start reading 29 00:01:52,800 --> 00:01:56,900 from from that. And we may do something like, okay, well if we get another 30 00:01:56,900 --> 00:02:00,900 error and we do F dot etc, etc. And then 31 00:02:00,900 --> 00:02:04,100 you get this long indentation of F's like this. 32 00:02:05,000 --> 00:02:09,700 This definitely not idiomatic. Go, what would typically see 33 00:02:09,700 --> 00:02:13,600 here is the reason people do this is because of the scope of f, they've done this 34 00:02:13,600 --> 00:02:17,500 declaration here and then F course is not valid outside of this 35 00:02:17,500 --> 00:02:21,400 block. And so then they get tempted to make a long chain of else's 36 00:02:21,400 --> 00:02:25,800 in idiomatic, go. What you would do is completely different, you would say here 37 00:02:25,800 --> 00:02:27,000 you would declare that. 38 00:02:32,900 --> 00:02:36,200 Now f is valid everywhere, your 39 00:02:36,500 --> 00:02:40,800 error return happens like this. So if anything goes wrong you immediately are returning and 40 00:02:40,800 --> 00:02:44,900 giving up or logging in error or whatever is appropriate and then you use 41 00:02:44,900 --> 00:02:48,200 f here. So this way, you're keeping 42 00:02:48,200 --> 00:02:52,900 everything as far to the left as possible along the main flow. Once you get a large 43 00:02:52,900 --> 00:02:56,300 indentation, it can be very, very messy to see it. 44 00:02:56,900 --> 00:03:00,700 Another thing, you sometimes see is a sequence of F's, where 45 00:03:01,000 --> 00:03:02,200 you could be better to use, 46 00:03:02,300 --> 00:03:05,600 Which statement so you might see something like this. 47 00:03:07,800 --> 00:03:11,900 So there's some some value in which is an integer. And you say, you know, if n 48 00:03:11,900 --> 00:03:15,800 is less than 0, then we do something else. 49 00:03:16,700 --> 00:03:20,800 If n is greater than 0, then do something else. 50 00:03:21,400 --> 00:03:23,400 If n is equal to zero 51 00:03:25,000 --> 00:03:29,800 and this is relatively easy to read, but a switch statement is even clearer. 52 00:03:29,800 --> 00:03:31,000 If you look at it like this, 53 00:03:41,100 --> 00:03:45,600 So, the switch keeps absolutely everything grouped together. You can easily could see the case. 54 00:03:45,600 --> 00:03:49,500 There's less syntax to look at, see what the actual switch statement cases are. 55 00:03:49,900 --> 00:03:53,900 So if you find yourself writing a long chain of effort of our users 56 00:03:53,900 --> 00:03:57,900 switch statements, instead these will fall through and he's acting the same way that 57 00:03:57,900 --> 00:04:01,800 the else operates. The sense that if this case doesn't apply the next one, will the next one. The next one. 58 00:04:01,800 --> 00:04:05,700 Well, and it's much cleaner. It's much less horizontal space used up. 59 00:04:10,200 --> 00:04:14,300 Another thing you'll find yourself working with quite widely and go programs is 60 00:04:14,300 --> 00:04:18,800 time. And luckily go, it has a very nice standard package called 61 00:04:18,800 --> 00:04:22,700 time and within that there is a type, which is a 62 00:04:22,700 --> 00:04:26,800 duration and so, we can just take a look at that. And 63 00:04:27,000 --> 00:04:31,300 adoration is actually a 10 in 64, underneath is actually 64 00:04:31,300 --> 00:04:35,800 representing nanoseconds. But what's good about it? Is that you 65 00:04:35,800 --> 00:04:39,600 can use it throughout your program to represent any time value without any 66 00:04:39,800 --> 00:04:43,600 Fusion. And I know that personally I've been confused in the past 67 00:04:43,700 --> 00:04:47,600 and introduce the horrible bug because I assume there's something that was an end was in 68 00:04:47,600 --> 00:04:51,700 microseconds. It was actually in milliseconds, so don't do the following 69 00:04:51,700 --> 00:04:54,700 kind of thing. Timeout, equals 70 00:04:55,000 --> 00:04:56,100 1000. 71 00:04:57,600 --> 00:05:01,500 So, a very common thing would be somebody to write that and put in comments that it is 72 00:05:01,500 --> 00:05:05,800 milliseconds. And then later on having forgotten that someone says, okay, I 73 00:05:05,800 --> 00:05:09,300 need to do a conversion on that. I'll multiply it by a thousand and now you've got a 74 00:05:09,300 --> 00:05:13,900 second and your timeout might be enormous at that point, if far 75 00:05:13,900 --> 00:05:17,600 safer thing to do is to use the time values. So, if you really 76 00:05:17,600 --> 00:05:20,800 want a millisecond, you can just use time. 77 00:05:22,100 --> 00:05:26,200 And you can come in and say one millisecond and then it's 78 00:05:26,200 --> 00:05:30,600 unambiguous what that timeout is meant to be and what the actual 79 00:05:30,600 --> 00:05:33,900 value is intended to be. Sometimes you'll see 80 00:05:34,200 --> 00:05:38,700 durations like this on the command line. And if you take a look at the flag back 81 00:05:38,700 --> 00:05:39,200 Edge, 82 00:05:42,700 --> 00:05:46,800 Within here, there is a duration value 83 00:05:47,300 --> 00:05:51,600 and it will take a value on the command line and convert it into a 84 00:05:51,600 --> 00:05:55,800 duration. And what's really nice about this is it will pass it and so 85 00:05:55,800 --> 00:05:59,700 you can actually type something meaningful on the on the command line. It 86 00:05:59,700 --> 00:06:01,400 uses a thing called 87 00:06:03,200 --> 00:06:07,700 Time pause duration. And this is a function that allows you to type in something 88 00:06:07,700 --> 00:06:11,900 like 300 milliseconds, or 2 hours 45 minutes. So let's just 89 00:06:11,900 --> 00:06:15,700 do a quick example of that. Let's bring in the flag 90 00:06:15,700 --> 00:06:16,500 package. 91 00:06:17,700 --> 00:06:21,900 And we're going to define a timeout variable. I'm going 92 00:06:21,900 --> 00:06:25,600 to use the flag package itself. So let's go back to 93 00:06:29,500 --> 00:06:33,500 so there's this duration, think so, Gosei flag a 94 00:06:33,500 --> 00:06:37,500 duration and we're going to call it time out, they cannot then we're going to give it a 95 00:06:37,500 --> 00:06:41,600 default value, so we give it a millisecond and I 96 00:06:41,600 --> 00:06:45,900 quite like to type 1 times, even those are necessary just to make it really clear that 97 00:06:45,900 --> 00:06:49,100 I meant one millisecond and I'm going to say 98 00:06:49,800 --> 00:06:53,600 timeout value and then we'll pause pause the flags 99 00:06:54,800 --> 00:06:58,500 and then we'll say timeout is and then 100 00:06:59,200 --> 00:07:02,800 Allow the time package to print out. So like that. So 101 00:07:03,800 --> 00:07:07,900 fairly simple little program is going to pass something. It'll be a millisecond 102 00:07:07,900 --> 00:07:11,900 if I don't type anything. That means it's optional and I will that's a 103 00:07:11,900 --> 00:07:14,400 pointer as well. Just make sure you do that. 104 00:07:17,100 --> 00:07:21,800 So the default timeout is one millisecond as you can see, the default string over the time package 105 00:07:21,800 --> 00:07:25,900 tends to print things out, rather nicely and I'm just going to turn this into an 106 00:07:25,900 --> 00:07:29,500 actual programs. And I've got a food program there and I'm going to 107 00:07:29,500 --> 00:07:33,700 say time out equals 1 hour. So now 108 00:07:33,900 --> 00:07:36,700 it's one hour and 300 milliseconds, 109 00:07:37,800 --> 00:07:41,900 200 nanoseconds. So that that is much, much better than spending 110 00:07:41,900 --> 00:07:45,600 any time tapping in integers and then converting them and making comments about 111 00:07:45,600 --> 00:07:46,700 it. Use those 112 00:07:46,900 --> 00:07:50,900 His duration things that are in the time package and in the flag package, 113 00:07:50,900 --> 00:07:54,600 and you'll find you don't have any headaches with the way in which we're doing times and timeouts. 114 00:07:58,700 --> 00:08:02,900 So, if you've been using go for a little while, you'll 115 00:08:02,900 --> 00:08:06,800 know very, well that there are no exceptions in go, you everything is done by 116 00:08:06,800 --> 00:08:10,800 returning errors and go has a fairly simple 117 00:08:10,800 --> 00:08:14,800 style for returning errors. There's the error type and 118 00:08:14,800 --> 00:08:18,700 it is expected that functions return errors and not other ways of indicating 119 00:08:18,700 --> 00:08:22,800 a problem. There is also, of course, panic and recover 120 00:08:22,800 --> 00:08:26,900 which some people like to use the basic rule of 121 00:08:26,900 --> 00:08:28,400 panic and recover is you never 122 00:08:28,700 --> 00:08:32,800 Use them. And if you find yourself tempted to use them, then 123 00:08:32,800 --> 00:08:36,700 it's probably the case that you're thinking, in a non idiomatic go 124 00:08:36,700 --> 00:08:40,800 fashion. So I just want to show you a few ways of returning arrows and a few 125 00:08:40,800 --> 00:08:44,800 things not to do, I'm definitely not going to show you panic and recover their 126 00:08:44,800 --> 00:08:48,900 things, you would not ever use. So, the standard way 127 00:08:48,900 --> 00:08:52,900 returning, an error from a go function is to return a return 128 00:08:52,900 --> 00:08:56,000 value. So let's have a cell do something 129 00:08:56,000 --> 00:08:58,500 and it returns an error. If something 130 00:08:58,700 --> 00:09:02,100 Goes wrong. And then in Maine we can pull out that error. 131 00:09:03,600 --> 00:09:07,500 So, that would be familiar to anybody who's written any go code. And the certainly anybody who's looked at the 132 00:09:07,500 --> 00:09:11,600 packages, will see that. And if do something needed to return something 133 00:09:11,600 --> 00:09:15,600 else, then it might return some other values. So, you know, 134 00:09:16,300 --> 00:09:20,600 my type and an error. And so, whenever your attorney 135 00:09:20,600 --> 00:09:24,900 errors, the truly dramatic thing to do is to return an error value, 136 00:09:25,500 --> 00:09:29,800 what you should definitely not do, is return a null pointer. So if you're 137 00:09:29,800 --> 00:09:32,600 coming from, say see you, 138 00:09:32,800 --> 00:09:36,900 Do something like this. You might say, okay, well what happens is if 139 00:09:36,900 --> 00:09:38,000 all goes well 140 00:09:40,100 --> 00:09:43,600 Then, you know, we're going to return some subtype. 141 00:09:45,500 --> 00:09:48,700 Like this, if something. 142 00:09:50,600 --> 00:09:54,700 Goes wrong, return nil, although go 143 00:09:54,700 --> 00:09:58,800 has nil pointers. They should not be used for returning errors in this 144 00:09:58,800 --> 00:10:02,500 instance, if you want to return an error and you're also returning a pointer, 145 00:10:02,800 --> 00:10:03,700 then do this. 146 00:10:06,700 --> 00:10:10,800 So something's gone wrong. You return nil for the actual type because you haven't actually got one 147 00:10:11,000 --> 00:10:13,400 and some sort of error. So we see there is 2 148 00:10:15,700 --> 00:10:19,600 And here, there's no error, so you can return nil. 149 00:10:19,600 --> 00:10:23,700 So, always always return an error and don't return a pointer 150 00:10:23,700 --> 00:10:27,900 to a nil pointer or even worse. Something else 151 00:10:27,900 --> 00:10:31,300 like a Boolean saying, you know, failed. 152 00:10:31,300 --> 00:10:35,900 So that that also is not idiomatic 153 00:10:35,900 --> 00:10:39,800 always use an ill error, or an error itself to return an error. 154 00:10:44,700 --> 00:10:48,800 If you spend any time looking straight, as it goes down to packages, you'll notice that lots of 155 00:10:48,800 --> 00:10:52,900 things Implement certain common interfaces. For example, there's a 156 00:10:52,900 --> 00:10:56,800 Stringer interface, which turns any struct or other 157 00:10:56,800 --> 00:11:00,900 thing into a string, which is useful for printing. And in fact, things like 158 00:11:00,900 --> 00:11:04,800 printf, use the Stringer interface to print something, there's 159 00:11:04,800 --> 00:11:08,900 also IO reader and I writer for reading and writing and in general, 160 00:11:08,900 --> 00:11:12,600 if you're creating your own structure and types, it can be 161 00:11:12,600 --> 00:11:14,100 useful to implement some of the 162 00:11:14,100 --> 00:11:18,500 Interfaces because many things will consume those standard interfaces. 163 00:11:18,500 --> 00:11:22,400 So, for example, if I made a simple type, let's call it 164 00:11:22,400 --> 00:11:25,000 pair with just as a pair of strings, 165 00:11:25,000 --> 00:11:28,500 and I created one of those. 166 00:11:28,500 --> 00:11:32,500 So, I can say, pair X is 167 00:11:32,500 --> 00:11:36,600 X, x X & Y is y. So I create one of these 168 00:11:36,600 --> 00:11:38,900 pair things and then I went to print it. 169 00:11:42,600 --> 00:11:43,900 So I can just print that out. 170 00:11:53,500 --> 00:11:57,400 Stop. It's not a string is the strapped. Is 171 00:11:57,400 --> 00:12:01,800 neuticles. Okay, so you get a Standard Printing of that thing. What's happened 172 00:12:01,800 --> 00:12:05,900 here is that go has tried to print out the structure by printing out the elements within 173 00:12:05,900 --> 00:12:09,500 it but maybe that's not what you really want. Maybe you want something better. So 174 00:12:09,700 --> 00:12:13,900 Implement one of the standard interfaces which is the Stringer interface and so 175 00:12:13,900 --> 00:12:17,600 we do that by just defining a method and the method is 176 00:12:17,600 --> 00:12:21,700 string that is the Stringer interface just returns a string 177 00:12:21,700 --> 00:12:22,600 form of this. 178 00:12:23,000 --> 00:12:24,300 And I can just do that with. 179 00:12:25,800 --> 00:12:29,800 S printf which turns interesting. And I can will say, let's print 180 00:12:29,800 --> 00:12:32,100 out. Each of the individual elements like this, 181 00:12:33,700 --> 00:12:36,200 So P dot X, PW Y, 182 00:12:36,200 --> 00:12:39,900 and we won that. And now 183 00:12:39,900 --> 00:12:43,700 there's all this changed here is this, interface is available and now 184 00:12:43,700 --> 00:12:47,700 I can write it out like that. So having implemented the Stringer 185 00:12:47,700 --> 00:12:50,600 interface anywhere that a string is required. It becomes automatic 186 00:12:51,300 --> 00:12:55,900 another way in which interfaces are useful is to use them as parameters 187 00:12:55,900 --> 00:12:59,700 to functions. For example, it might be tempting to write a 188 00:12:59,700 --> 00:13:03,700 function that loads the values in this string from a file. So, you 189 00:13:03,700 --> 00:13:07,900 Might be say, I've haven't given a pair. I'm going to load X and I'm going 190 00:13:07,900 --> 00:13:11,800 to load it from some file, a return, an error, 191 00:13:11,800 --> 00:13:15,500 if that happens, that's fine. And you could certainly do that, but it 192 00:13:15,500 --> 00:13:19,900 restricts you to using an actual file. A better way to do, 193 00:13:19,900 --> 00:13:23,800 that would be to use an IO reader, then anything that can be read 194 00:13:23,800 --> 00:13:27,800 from can be put in there, including an OS file. So, now, as file will 195 00:13:27,800 --> 00:13:31,800 work as well. Now, the reason that might be particularly important is that when you come to 196 00:13:31,800 --> 00:13:33,500 write your test suite for these, 197 00:13:33,600 --> 00:13:37,900 Visual functions, you can substitute something like a byte buffer which you filled with 198 00:13:37,900 --> 00:13:41,800 test data for an actual file and you're not actually messing around with files on the 199 00:13:41,800 --> 00:13:45,900 file system. So interfaces will give you a great deal of flexibility in 200 00:13:45,900 --> 00:13:49,800 how your structures actually operate without the tying yourself to 201 00:13:49,800 --> 00:13:51,200 particular, concrete types. 202 00:13:55,300 --> 00:13:59,200 Another aspect of go idiomatic, go 203 00:13:59,600 --> 00:14:03,900 use how to write comments. And if you look at the Go packages, again, they're always 204 00:14:03,900 --> 00:14:07,800 a good source of what sort of go. Should I be writing? You'll see a very 205 00:14:07,800 --> 00:14:11,000 distinct style in terms of the way in which packages 206 00:14:11,000 --> 00:14:15,600 functions and structures or types are commented and it's worth. Just 207 00:14:15,600 --> 00:14:19,300 going over that very briefly so that you end up writing similar sorts of 208 00:14:19,300 --> 00:14:23,500 code. This is also very important because go doc or use that 209 00:14:23,500 --> 00:14:25,200 those comments to actually display. 210 00:14:25,400 --> 00:14:29,900 Information about packages that you yourself create. And so using the same style makes 211 00:14:29,900 --> 00:14:33,900 everything feel very consistent. So let's suppose we make a package 212 00:14:33,900 --> 00:14:37,300 to represent a dinosaur. So we Sol have something like 213 00:14:37,400 --> 00:14:41,700 package dinosaur. The first thing you'd have is you'd have a package 214 00:14:41,700 --> 00:14:45,500 comment. And this always comes right before package of the top and you would 215 00:14:45,600 --> 00:14:49,700 typically would start something like this package dinosaur and then an English 216 00:14:49,700 --> 00:14:53,700 sentence that describes what it is for. So we could say something like that 217 00:14:53,900 --> 00:14:54,700 provides. 218 00:14:56,200 --> 00:15:00,400 Functions for creating and manipulating. 219 00:15:03,000 --> 00:15:07,400 Dinosaurs. So something like that and 220 00:15:09,600 --> 00:15:13,700 so that becomes very clear. That wouldn't go. Doc will come out as the actual documentation 221 00:15:13,700 --> 00:15:17,800 for that particular package. And then within it, of course you might have some type so we might have 222 00:15:17,800 --> 00:15:19,300 a dinosaur 223 00:15:21,100 --> 00:15:25,300 Which will be closed until probably have a name and it might have a 224 00:15:25,300 --> 00:15:29,800 weight and it might have whether it's a 225 00:15:29,800 --> 00:15:33,300 herbivore Etc. And the way in which this would get 226 00:15:33,300 --> 00:15:37,900 commented is with again with an English sentence but with a very 227 00:15:37,900 --> 00:15:41,700 distinct style, it would always start with something like a 228 00:15:41,700 --> 00:15:45,400 dinosaur is and then go on to describe what it is. 229 00:15:45,700 --> 00:15:47,000 So a single 230 00:15:47,900 --> 00:15:50,700 Dinosaur with name, wait. 231 00:15:52,000 --> 00:15:52,700 And weather. 232 00:15:54,200 --> 00:15:55,000 It is. 233 00:15:56,100 --> 00:16:00,800 A herbivore. So always your writing English sentences for these things and 234 00:16:00,800 --> 00:16:04,400 let's suppose the on a dinosaur, you had a particular method. So 235 00:16:05,100 --> 00:16:09,500 let's have a dinosaur method and this is a dynasty this will 236 00:16:09,500 --> 00:16:13,900 output for example the name of the dinosaur. So right 237 00:16:13,900 --> 00:16:16,400 name is going to write the name to an IO writer. 238 00:16:19,700 --> 00:16:23,800 Return an error Topsy. Prevent that. And 239 00:16:24,100 --> 00:16:28,900 these always also have a very similar style. These always start, actually, with the same name as the 240 00:16:28,900 --> 00:16:32,700 particular method. So, right name, write the name 241 00:16:32,700 --> 00:16:33,400 of the 242 00:16:34,300 --> 00:16:38,100 dinosaur to the provided IO writer. 243 00:16:38,100 --> 00:16:42,300 So, throughout the packages, you will see this style of package level, 244 00:16:42,300 --> 00:16:46,800 comment structures being commented with a something like that, proper English and 245 00:16:46,800 --> 00:16:50,900 then individual methods being commented in the same way. And if you follow the same style in your 246 00:16:50,900 --> 00:16:54,900 own code, what will happen is that though doc will display it correctly and also your code will 247 00:16:54,900 --> 00:16:58,800 look like other go code and a big aim of idiomatic go and go 248 00:16:58,800 --> 00:17:02,900 format and even the packages that come with go is to give 249 00:17:02,900 --> 00:17:04,000 all go code of some of the 250 00:17:04,300 --> 00:17:08,700 Dial. So, there's no difficulty reading someone else's code, so if you do this, you'll find that others can 251 00:17:08,700 --> 00:17:10,600 quickly. Pick up what your package does.