 Hi everyone! That was bad. That was really bad. All right, let's try that again. Hi everyone! Sweet that was so much better the second time Thank you all for coming out. I know the weather was crappy earlier, but I'm excited that everybody's here Today I want to talk about intro to go So this is me. That's me on Twitter. You should follow me. That's a gopher over top of my head If you don't actually want to pay attention to what I'm saying Every slide has a gopher on it. So try to find the gopher send every single slide a little bit about me I work for a company called HashiCorp For this of our tools are written in go. I've been doing go since About September of this year. So I'm definitely not an expert, but I've written a couple Pretty largely used tools at this point So I had to like print out this joke because Justin did on Twitter apparently my last name is also has a go in it So I felt the need to emphasize that There's no relation. I promise So like I said, I work for HashiCorp If you don't know what HashiCorp is you may recognize like vagrant packer surf console terraform These four are actually written entirely in go. Maybe a little bit of bash mixed in there But what most people don't know is there's actually a little bit of a go in vagrant Some of the binaries and vagrants actual launcher like the vagrant thing that you type is actually written in go So all five of our products have some resemblance of go so What I wanted to talk about first was do you like a history? So a little bit about how this is structured is we're gonna go through like kind of non-technical things Why go how does it compare to other things? And then I'm actually gonna go through some examples I want to be absolutely clear that you're not going to come out of here with a degree in go One because that doesn't exist and two because I only have like a half an hour But please if you have any questions write them down feel free to ask me afterwards, etc so It all started in like 07 when rob pike Rob Thompson and some other dude who I can't remember right now Yes, and I wrote it down. It's in the slide notes But rob pike is kind of the like The face of go at least now So in 07 they kind of got together And they said the existing state of languages Post some problems We'll talk about those in a second. So the modern languages you had like your C's and your javas Ruby and python no jas was starting to make an approach scala was this like hybrid java thing Javascript was coming out as like a first-class language web apps were becoming the future and apple had kind of started talking about objective c and then later on In like what 2011 swift came out so in 2008 You know they identified these problems and had like a whiteboard sketch of what the language would solve So the problems with the modern languages of the time were You had to choose between efficient compilation Efficient execution and ease of development. So if you look at something like ruby and python very very quick to get a prototype out Very very low barrier to entry for developers and engineers but not the most performant in production not the most stable in production and Definitely not the cheapest to run in production Compare that with something like c or java which has like an incredibly high barrier to entry And usually you go to college to learn c or you spend months learning it It takes a really long time to compile like you have to somehow deploy it. But once it's deployed Because it has type safety and a whole bunch of other things like the chances that it crashes in production are much lower It's a much more reliable and safer tool And the problem was you really couldn't Pick all three of those. It was really difficult to find a tool that even had two. It was mostly one Do you want your developers to move quickly and your operators to have a really bad day? Or do you want your developers to move very slowly and your operators to have a very safe day? Type safety was something that's on the rise like python and ruby like Zero cares to what type it is you can assign x to a string and then the next line assign it to an integer Compare that with like c and java which are super super strict You have to declare your type going into the variable declaration And scala was kind of this weird hybrid approach where you could like declare the variable But then it was like set as that type forever until you undefined it So those were the problems with like modern technologies at the same time Technology in and of itself was kind of rapidly evolving No longer did we have monolithic giant applications? We're moving into this era of microservices where we have these small kind of item put in applications that Basically act like i-nodes on a graph they take input and they produce output so We're moving towards a modern era where kind of none of these tools really fit what the You know the original authors of ghost saw as the trend in technology So they came up with these list of requirements The first is that it has to compile incredibly fast And it has to execute incredibly fast So your code can be incredibly fast, but it takes two days for your application to compile You can't ship and deliver in any reasonable amount of time It has to be highly concurrent again. We work in a microservices model Concurrency we look at like modern computing. We're operating on multiple cores. We need to take advantage of all of those cores Built-in garbage clushing because ain't nobody got time to write like free Support for dependencies because they recognize that community was one of the things that made ruby and python much stronger Than cian java was the ability to just grab this community tool and bring it in and use it Without really having to understand the entire system And it had to be good enough for google It had to be good enough that this was something that google could run in production on their systems safely and sanely So 2009 is like the first official birthday of go There are reports that it had been used internally before that But that's when like the official release happened It was open sourced. It was made public and people started using it And now we're in 2015 and a whole lot of stuff has happened Both in computing and in the go programming language since then So that was like the brief history Now we're going to talk about go as a language what it has and what it doesn't have So go has this incredibly incredibly solid core. There's some puns coming up in these pictures. Just to warn you guys um Go kind of has this mantra of like batteries included You see that on the the go lang documentation and like all of the go textbooks, etc They use this batteries included built-in json serialization built-in web server kind of built-in everything The primitive support is really great And then there's also abstractions on top of those primitives that are built into the core language They're well tested. They're highly performant and they're well documented Go has a very robust community Get it nerds You're laughing at me, um, it's okay So grow has an incredibly robust community We'll see in a little bit the way that you import a dependency is you just specify the url for it So pretty much any go library that's on github. You can just import as a dependency There's also lots of forums the go lang mailing list the go nuts mailing list, etc It's all public. It's all like vibrant with people who are excited And they love using the language It has incredible performance It's not quite as fast as c but it's like a bajillion and five times faster than ruby and a bajillion and four times faster than python It's and it and it has incredible performance for authors as well So it doesn't just run quickly on the actual hardware. It runs it writes itself quickly from the engineering perspective It has built-in linting and formatting Which is a big one for me who has ocd I don't have to argue with people. So this is actually a console template Which is one of the libraries i've written on the left Is like if you just write kind of crappy go code and you don't worry about your indentation or your white space As soon as you run go format, it'll like automatically indent things It'll automatically add white space where appropriate. It'll line things up in your structs So everything's vertically aligned If you have any semblance of ocd go will make you very very happy There is no gray area. There's one style and you follow that style The advantage is that go will apply that style as best it can. So You never really have to argue and you're not wasting time like tweaking things The the formatter will do it for you It's very easy to build cross-platform binaries with a few exceptions As long as you're not like binding to like very very low level system calls, which is something that's possible You can basically cross compile to any platform including windows And this was one of the major selling points combined with like speed and Speed to write and speed to run of why the majority of our tools are written in go If you've ever tried to deploy cross-platform ruby, it's very very difficult, especially for the windows story Go makes it actually Incredibly painless There's a bunch of tools out there some of we write a tool called gox Which is a go cross compiler. There's like go xc But basically it's one command and you get spit out an exe file You get spit out like an actual binary file for various operating systems And it's super super fast and super easy Go has built-in gc for people who come from like a sea land. That's kind of scary. They really like their malloc and they're free But from people coming from like a ruby and a python background They they love the fact that they don't have to think about memory management They don't care whether their structure is going to go on the heap or the stacked It doesn't actually matter In modern computing, we have so many resources available that those types of low level optimizations are generally not worth the trade-off of Actually having to think about it and go is incredibly great at optimizing those types of decisions for you So go does not have a pretty website I personally find their documentation very difficult to follow not because it's well like not well documented But because the layout is like one ginormous html page and you have to scroll or like click through a links to try to find anything I think the documentation is great. I think the way it's laid out is not the greatest There's no support for generics And i'm not going to go into the reasons why or why not but Unlike java, you can't just like have the generic interface so that you can apply to things Which means if you're trying to make a set for example That takes some type of object It's very very difficult because you have to generate a unique type of struct for each Each set container that you want And finally go has really terrible seo If you try to google go Yeah, which is ironic because it was created by the search engine that doesn't show it in the results until like the third thing down here Pro tip if you are working on go go lang all one word is what you want to search for It makes it much easier to find things But those are kind of the three drawbacks that I find with go is without fail every time I try to find something I google like You know Go big int and I get like some video game back. I'm like go lang big int. Oh, there's the documentation cool So very briefly, how do you install go? It's this Incredibly super painful process you download the binary and put it on your system If you want to compile from source those instructions are available I think as of go one four like goes compiler is written or go is compiled with goes compiler So it's super meta So like go compiles itself The next thing you do after you install it is there's these two magical environment variables one is go path one is go root And this is kind of like your working directory So if you've ever worked on like ruby or python, this might be Kind of foreign is because you just have projects wherever they are and whatever your working directory is just your working directory But with the way that go manages dependencies it has a very very strict file hierarchy And it wants to know this is where i'm going to do my go work and a lot of people that's just like home slash source Let's go some people. That's like some nfs share. It doesn't really matter What matters is that all of your go development happens within this go path The advantage to being an environment variable is that it makes it really easy to write go version managers Because all you have to do is change that environment variable and all of a sudden you have a new version of go You're pointing to a different set of dependencies, etc And then the command line tool Unsurprisingly is go So you run go this is the help output You can see some of the things in here like build clean format is that linting function that we talked about earlier List and then there's some in here like vet And you can also run go tool So if there's like third party tools that you've installed that do particular things you can execute them with the tool command And I guess now we're going to jump into code because that's what this slide says So the very first thing is this is go. It's kind of hard to see but I have like file names down here So this says example go The very first thing to see is there's package declaration So everything in go has to belong to a package Kind of like in java like main is the main package. So this is like the top level The main function can only live in the main row. The main function is only executed from the main package Dependencies are imported with this import statement Things that are from the standard labor imported using just their name Things that are third party dependencies are imported using their url path So for example, if I was to import a third party library from github I would say import github.com slash bill slash Go library And that would automatically be pulled in when I run go get which is the dependency manager that's built into go Comments are Just two forward slashes Function definitions are done with the funk keyword f UNC Even if you have no arguments, you're required to have parentheses, which is something that you know ruby allows you to be optional You need egyptian style curly braces. It's like strictly enforced when you run go format all of your curly braces become egyptian style and It's it's dot oriented. I never really figured out what the actual word was but You have it's read from, you know left to right it encapsulates from inside out. So Cool Uh, oh, and then when I were to if I were to run this so if I were to like actually save this as example go I would build it by running go build And I think that took like 0.000 seconds on the system And then you invoke it as a binary. So you just run an example And you can see that the output here is hello world So this very basic function declares a main package inputs the formatting package Has a comment solely for demonstration purposes and then has the main function, which just prints out some strings The main function like this main function is special when it lives in the main package. That's what gets executed when the binary runs Cool And as you can see go is like incredibly fast the whole execution of that binary including load time took like 7 1000ths of a second Used 54 cpu So pretty fast So here's a more complex example, and I'm going to run through it. So don't immediately jump back I find that people learn best through examples at least I do so everything here is kind of example driven So the first thing is like totally ignore all of those import statements. We'll talk about those in a little bit The first thing here is this buff i o new reader taking in os.standard in So what this is doing is this is essentially asking for user input There's a couple different ways that you can ask for user input This is using a buffered i o reader and it's reading from standard in so os.standard in is like what you type on the command line There's also os.standard out which is standard out and standard error We're essentially reading until the new line character So basically read text until the user presses enter or carriage return If I was writing something like truly cross platform, I'd probably check for like slash r there as well for windows carriage returns And then finally there's like this whole magical function which I'll explain it a bit But at the end of the day the result of this Text so whatever the user typed in is going to be printed Back out. So I want to like decompose this together so The text comes in and then we call this like trim space function on it The reason we call trim space is that the read string is going to include the new line character And we don't really want to include the carriage return back in the output Then we're going to put it into a print function. So if you've used like python or c printf And sprint f are like pretty standard This is how you do interpolation in go. So you don't have like rubies pound curly brace within a string everything's done with sprint f Or like other f functions and finally we're outputting that to the terminal in this case so to give you like a real example if we took away all of the Extra garbage that was in here and we got rid of the reader and we just set this to a static string So this is essentially simulating the user typing in high and hitting enter What we would have is the text would come in just like that We would call trim space on it, which is going to get rid of the new line new line character Now we're going to sprint f. So we're effectively interpolating high into q percent q is a special Function in go that basically It prints out the best representation of the object which for strings is a string quoted string So you end up with this So you have my name is high and those are escaped. So things are escaped with a backslash And uh They compile to this and then sprint f Yeah, forward and then ultimately that prints out like your name is high. So back tracing As we apply these functions you get The final result and this error checking is something you'll see a lot in in go. There are no exceptions in go Errors are first class objects. They're a thing you can query them You can write methods on them. You can define your own error types Go has this notion of a panic, which is like something really bad happened It's not quite the same as a seg fault, but you can think of it as like a seg fault It's where like a control that should have not happened happen So if you try to like access an index out of range, you're going to get a panic So If I were to compile and run this and I typed in high you would get your name is high with the quotes Just as we saw when we broke it down Um, and I'll have all these examples on github afterwards. So if you want to like Kind of follow along try it out. Um, you're definitely more than welcome to So going back to this example, um, I kind of glanced over this magical import So there's a whole bunch of stuff going on in here. We're importing buff.io Format os and strings And how do we like what is that doing? How does that at all relate to what's going on in this main function? Well, the name of the package is what gets imported in the first call. So Unlike your traditional object oriented program Programming languages in this case buff.io is not some instance You're not calling a method on an instance. You're actually invoking a public method on the buff.io package called new reader Similarly for strings strings is a package and we're invoking the public trim space function Uh, and you can see os is used here And fmt is used a couple places for you know printing the original output and then printing the final output as well as any errors that occur If I were to add an additional import for example This is um, i.o. Udall, which is a handy library for like reading files Uh, and I were to try to compile this ghost compiler is very very strict And it's going to yell it's going to yell at me and say hey you imported this package that wasn't used And it does that for two reasons first. Uh, it likes to be annoying and second It's because you don't want to have all of these extra imports and generating these like 10 gigabyte binary files that you ship around when you're only using Two megabytes worth of dependencies. So ghost compiler is incredibly strict One thing that I really wish was in development if there was a flag you could pass to go That was like ignore the strict compiler and then like finally when you're ready to build turn on the strict compiler, but It's not there. Um, so sometimes it's a little bit painful for developing Where you go to run go build and it's like you're not using this package anymore You have to go and like delete that line and then compile it again But ultimately it's it's like good for the end result of the program. Uh, and it's definitely a trade-off So I wanted to look at it an example Um, and obviously like the number one example in programming is hello world. We did that already. The number two example is fizzbuzz So, um, this is fizzbuzz in a language that does not go. This is fizzbuzz in ruby Um, and if you're not familiar if you are familiar with ruby, this looks super simple and familiar if you're not Basically, we're going from one to max max as a parameter to this function Uh, if it's divisible by five and three print fizzbuzz if it's divisible by three print fizz five buzz Otherwise print i is anyone not familiar with the fizzbuzz problem is um, like a very common interview question that is, uh, basically it's this Given a list of numbers from one to n if the number is divisible by three and five print fizzbuzz If it's divisible by three print fizz if it's divisible by five print buzz Otherwise just print the number. So for example, you would have what one two fizz five four buzz six And then like 15 would print fizzbuzz Because it's divisible by five and three So the same result here in go looks pretty much identical So if you if you take away like the fact that this is deaf and this is funk And the fact that this is an up to versus a for loop. They're pretty much identical The the modulo check is identical. We're using and and for bullions We're printing using fmt And I've obviously left out the import statements here for in the package declaration for simplicity But you can see that it's very very similar to what you might see in like ruby or python So side by side, um, they actually map line for line. They have the exact same number of lines And this is a super simple example I just kind of wanted to compare something that people are generally familiar with How you would do it and go and how you would do it in ruby cool Here's like another variation So in this example we're using else and like elif statements You can also use like in ruby. It's called next which means stop termination and go to the next iteration and go That's called continue So this basically short circuits the loop. So if this conditional is met, we don't ever go down here It's like another way to write an else statement basically And it starts back up to the next integer Cool. Um, so now I want to look at like a little bit more complex of an example How many people are familiar with like the fibonacci sequence? Right, so it's just taking two numbers adding them together. That's the next number in the sequence So here's how you would recursively implement fibonacci and ruby Super simple If the number is less than two So one and zero just return one and zero otherwise return n minus one plus and minus two recursively calculating those values This is the exact same thing and go should come as no surprise It's I mean, it's literally the exact same thing If you replace curly braces with ends and funks with defs, it's the same I guess the biggest difference is you have to declare your return type as well as your input type So the fun part here is Um, coming up next are benchmarks. So which one is faster? How many people think go is faster? Okay, how many people think ruby is faster? Cool. So go took 1.027 seconds Um to generate the 40th fibonacci number. Um, so how many instruction sequences is that on the stack? Cool trivia question I'll let you guys figure that out and I have stickers for oh, that should have been my trivia question Next time Uh ruby took 17 seconds almost 18 17 and a half Um, you can see that they're both at 99 cpu utilization On average, but ruby was a 99 cpu utilization for 17 seconds go is that there for one second? You can also see what's interesting is the actual like boot time of go is 0.01 seconds spent in the system as opposed to ruby Which sent like 0.04 seconds in the system So ruby itself actually takes a long time to launch these numbers are strikingly different in in windows Like this is like 0.2 seconds in windows and like A full like 0.8 seconds in uh windows with ruby because spawning ruby processes in windows is unbelievably slow Um, but we can make this super efficient. Um, if we just choose a different algorithm So it turns out that recursion in general is really really like not performant You have to shove a whole bunch of stuff onto the stack And there's like all of these instruction sequences and then you just unwrap the whole thing only to return one result um, so go can efficiently Reassigned variables on the fly So this is an incredibly fancy way of generating a fibonacci number which sets i and j to 0 and 1 respectively So you can do multiple assignments just like that as long as the number of variables on the left matches the number of variables on the right and then this is a simple for loop that's basically iterating like Max times and swapping i and j setting i equal to i plus j and j equal to i and it does that all in one instruction sequence So it's super super fast. So there's uh only 43 seek 45 instruction sequences that happen So fib of 40 with this algorithm Takes 0.004 seconds So it's super super fast This same algorithm in ruby, which is also possible takes i think 1.2 seconds. I don't think i made a slide for it Didn't But it's it's noticeably faster, but also noticeably slower So how long do you think it would take to count the 1000th fibonacci number keeping in mind that you need to also calculate The 999th 998th all the way down to the 0th fibonacci number Yeah Because we haven't changed the same number of instruction sequences. It's exactly the same um We're just iterating more times and the compiler is super super good at optimizing these instructions so If you're curious, that's the 1000th fibonacci number um I'll tell you how I cheated in a little bit. Don't worry What if uh, what if we didn't want to actually like return the number? What if we wanted to return some type of generator? In java, it'd be like an iterator In closure. I think it's called a closure That basically I can just keep asking for the next fibonacci number pretty much indefinitely. I just want the next one So I have this like kind of skeleton function called fib generator. It's going to return Something Uh, so let's kind of build this out together. So we're going to have some closurey thing um I had to use a word closure because Yeah um And it has to do that operation that we did before so it has to do that like i and j being initialized to 0 and 1 And then like swapping j and i So this is the same thing that was in before but I've put it in the loop declaration So we're assigning i to j 0 and 1. There's no Invariant and then i and j are equal to i plus j and i so that actually happens in the for loop gets evaluated during each iteration And we need to like do something with i because during each iteration i is the next fibonacci number in the sequence So we can wrap this in a closurey thing Go has support for anonymous functions. So the same way we declare like funk fib generator We can declare an anonymous function. It has no name And this is a full closure And we can run that in the background using what's called a go routine So if you shove go in front of any function and immediately backgrounds And it runs in a go routine, which is not a thread. It is not a background process. It is a Highly optimized and very difficult to explain construct It's safe to think about them as threads, but they don't operate the same as threads So we have this go routine. So when someone calls fib generator We're basically firing off this background job that is still managed by the parent go process that generates these numbers So now we need like this thing that returns the magical generator And what could that possibly be? We need to somehow Send the data from this go function that runs in the background We're basically want to pipe this data back up to the parent process So c exists outside of the closure and the closure has access to c And we want to be able to send data back up to c from this background process So that we don't block the main thread So other execution can occur and this other stuff is happening in the background But we need a way to still communicate between those two processes And finally we want to return whatever that magical thing is And that magical thing is Like what could it possibly be? I'll give you a hint it starts with a c because I use that variable name And those are channels So channels and go are something that's incredibly unique to go And it's a way to essentially pipe information and share state across multiple go routines. So what does that look like? Just like an int or you know a struct You have channels the keyword is ch an and channels have types so everything can go has a type So i'm creating a channel of integers, which means the only thing that's going to come over this channel are integers I could send objects over channels. I could send Entire functions over channels. So you could have a channel that returns functions, etc Now this is a read and write channel And we'll see how you read and write from a channel a little bit But i'm actually just going to return a read only channel because I don't want The parent who grabs this fib generator. I don't want them to be able to write numbers to my channel They should only be able to read numbers for my channel And this is this is the way that we write to the channel So it's this like less than Dash thing and these read from right to left unlike the rest of go. So we are pushing i onto the channel Which basically is sending data from this sub process up to the parent process and then we're returning that channel So how might that look in a main function? For example, we would create a new fib generator So this here is actually returning a channel Right because the result from function is or from fib generator is a channel of integers that's read only And then 25 times we're printing the result of fib How do we get a value off of a channel? Well, it's just the opposite Direction or not the opposite direction. It's just the opposite side of the less than dash thingy So the arrow always points to the left There is no such thing as a right pointing arrow and go Whether it's on the left side of the function or the right side of the function determines whether it's a read or a write So if it's on the left, it's a read if it's on the right. It's a push So this is actually a very simple way of generating 25 fibonacci numbers Without blocking the main routine. So if other work was happening in the main routine This go function is running in the background generating numbers But does anybody see a problem with this approach? There's like one very big problem Yeah So if you try to read from a closed channel, you'll get a panic that's true, but you have to close a channel They don't just auto close Okay Okay, there's also there's another really big one That's true, but that wasn't what I was going for so this uh, yeah, but so Um, this particular block for example Uh, is going to run indefinitely and consume lots and lots of cpu resources by pushing on to this unbuffered channel It will I promise I was at 100 cpu usage um But we'll talk about that after and I will I will use this to prove a point Um, so this is basically an indefinite loop and it's going to run and try to push onto this channel forever Um, go has this notion of buffer channels, which is Effectively you can tell go to only hold so many items in the channel and then to block the push on the channel until There's a free space So you can find and think of it as like an array and I have for example 50 elements in this array And don't push a new item onto the array until there's space For me to be able to push on And in this case if there's 50 items in the channel's buffer right now And this go function attempts to write it will block while trying to write 51 onto that channel Thus we don't have this like infinite loop going on in the background Uh, so this is how you create a buffer channel. Um It's just a number. It's an int. I think it's a unit. Um and It can Basically be any size. Um, or you can just go for like the unbuffered Component it really depends on what you're looking for Like I said, that's going to block so Moving on to talk about structs, but we're going to keep with the same example So a struct is kind of like a class. It's not a class, but it's kind of like a class It's like a c struct in that You can define types and you can define properties as well as functions on a struct So this is where go is like kind of a little bit object oriented But go is not an object oriented language. It doesn't have inheritance et cetera One thing that's super interesting and a little bit confusing if you're just reading go code Is how do you declare public versus private functions? It's not like immediately intuitive And that's because it's all with capitalization So capital variables and Structs and functions are public and lowercase ones are private So if I create a function with a capital p called public funk It becomes publicly available within the package. It's package public If I create a function with a lowercase p like private funk, it's Package public or it's like locally public but package private So you cannot access private funk outside of this package, but it's fully accessible within that package So other classes or other other go files, et cetera can still access that function But as soon as you try to import that as a dependency private funk is no longer available And the same goes for fields on structs as well as the structs themselves So we're going to keep this struct private just for the purposes of this demonstration In general you have like some type of an initializer when you have a private struct like this So I created an initializer called new fib. It takes an integer Which is the size of the buffer and it returns like a pointer to That should be a lowercase f a pointer to the fib struct and an error There's actually no error to return here, but In general things return both like their pointer and any errors that occur So just kind of following the go standard here We make a new fib struct, so we allocate a new fib struct We set its buffer equal to b make a channel So this is the same thing we saw earlier and then spawn off this go routine in the background pushing onto that channel and then Returning instead of returning the channel this time we're returning the actual Fibonacci struct or the fib struct in this case and then nil for no error So nil is like the equivalent of null or nil in other languages And the way we would Use this from like a main function in the same package is we would create a new fib check if there's an error And then basically read from that channel the problem is reading from that channel because it's private isn't accessible to Other people outside of this package. So maybe that's okay, but let's just hypothetically assume we're building a You know the fibonacci generator that is going to be used by other people So what we really need is we need some type of function that return a public function that returns the next number in the sequence so Next is that function it starts with a capital n so that it'll be public in the package And we can basically return a read from that channel So we're effectively abstracting the read from the channel into a function And that function returns an integer as opposed to before where we were just directly reading from the channel And instead of this which is what we had before we now just call f dot next which will read the next value from the channel And I added a sleep in here just for like the purposes of running this and you can see that You kind of get the same result But as we go along you start to get some really creepy results. This is where I said that I cheated earlier is because Goes max int I don't remember off the top of my head, but the max uint is like Eight times ten to the ninth. I think and then it just starts wrapping back over So you get kind of weird crazy negative numbers as integer arithmetic becomes very difficult So what I did in my actual example that generated that really big number was I used a package called Oh, this is my favorite meme ever Yeah, it's that number whatever that number is That's the maximum uint 64 and we wrapped that so we went back around I used a package called bigot which is built in to go core Which allows you to deal with like incredibly large numbers efficiently So my my routine which I can share on github is slightly different than the code that I put up here But I wanted to provide something that was simple and not bog you down So that's what I meant earlier when I said I cheated So if you want to learn more And I haven't like totally killed your love of go at this point You can go to tour dot go line dot org I will say that the tour of go is I think 80 chapters now And it takes you from like the very basic. This is how you print something and the final is building a web crawler And you very quickly go from this is how you print something to this is how you build a web crawler And it's a little bit frustrating at first because you're given like You're given like here's two paragraphs of text about how functions work And then you're given this like incredibly hard problem that you don't actually see how relates to those two paragraphs of text But at the end of the day, it's actually super helpful because you get to like think like a go programmer Which is something that I'd never done before so it was super helpful. I was just frustrated at first So if you are doing the tour of go lang and you find yourself getting frustrated Just like take a step back or like actually ask on like the go mailing list or in like irc Or you know ping someone who you know is good at go and say hey, how did you solve this? The answers are available people post them on gists and stuff But I would discourage you from doing that until you have your own solution and then you can compare One thing about go just like ruby and python. There's usually like Probably 10 to 15 different ways to do the same thing. Sometimes it's more performant. Sometimes it's just a style thing So kind of finding out what works for you is definitely varies With the type of problem you're solving as well as you as an individual So this is me Again, you can follow me on twitter. Thank you for listening to me talk slash rant As we talked about this morning, I'm never rant about anything And I wanted to end with this amazing video that is going to play with sound now Maybe