Writing an App with Go - Instructors: Gustavo Niemeyer

1 === ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - https://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Questions in #ubuntu-classroom-chat || Event: App Developer Week - Current Session: Writing an App with Go - Instructors: niemeyer http://pad.ubuntu.com/ep/pad/view/ro.vJnRUh5vWNI/latest 2 [20:00] <ClassBot> Logs for this session will be available at http://irclogs.ubuntu.com/2011/09/09/%23ubuntu-classroom.html following the conclusion of the session. 3 [20:01] <niemeyer> Hello everyone! 4 [20:01] <niemeyer> Sorry for interrupting the amazing set of questions zoopster :) 5 [20:02] <niemeyer> So, I'm here to talk about how to develop apps in Go today 6 [20:02] <niemeyer> This is the Go language not the game board obviously 7 [20:02] <niemeyer> http://golang.org 8 [20:02] <niemeyer> I'll be using an Etherpad over the conversation to put content 9 [20:03] <niemeyer> Please follow up here: 10 [20:03] <niemeyer> http://pad.ubuntu.com/ep/pad/view/ro.vJnRUh5vWNI/latest 11 [20:03] <niemeyer> nigelb, pleia2: Can we have that in the topic? 12 [20:04] <niemeyer> Please feel free to ask any questions as I go.. I'll be happy to talk 13 [20:04] <niemeyer> I don't have a specific script in mind, so I'll be happier to solve doubts and to talk to you than to be in a monologue presenting the language 14 [20:04] <niemeyer> There's plenty of material online to follow, and I'll be providing some pointers 15 [20:04] <niemeyer> So let's make the most of our time here to exchange ideas and solve questions 16 [20:05] <niemeyer> So 17 [20:05] <niemeyer> My name is Gustavo Niemeyer, and I'm responsible for the area of Amazing And Unknown Projects at Canonical 18 [20:06] <niemeyer> Was pushing Landscape for several years, and then when it started to get well known I moved to the Ensemble project 19 [20:06] <niemeyer> https://landscape.canonical.com, https://ensemble.ubuntu.com 20 [20:06] <niemeyer> Now Ensemble is getting well known, but I think I'll stick for a little longer ;-) 21 [20:07] <niemeyer> Little more than a year and a half ago I started playing with Go in my personal time 22 [20:07] <niemeyer> Not really expecting much 23 [20:07] <niemeyer> I've been doing that with every other language for a while.. Haskell, Erlang, Java, etc 24 [20:07] <niemeyer> Python was the last language to hook me up for a long time as the "preferred whenever possible" choice 25 [20:08] <niemeyer> After I started some projects with Go, though, I started to really appreciate what was there 26 [20:08] <niemeyer> It didn't really hook me up for any _specific_ feature, though 27 [20:08] <niemeyer> What's most amazing about it is really the sum of the parts 28 [20:08] <niemeyer> In fact, it's a pretty simple language 29 [20:08] <niemeyer> So most aspects you'll see there will be a "Ah, but that's done elsewhere too" moment 30 [20:08] <niemeyer> and that's surely the case 31 [20:09] <niemeyer> The detail is precisely that it's putting all of those things in _one_ language 32 [20:09] <niemeyer> In a very nice to digest fashion 33 [20:09] <niemeyer> For instance, 34 [20:09] <niemeyer> Go is statically compiled, but has good reflection capabilities 35 [20:09] <niemeyer> It also has what I like to call "static duck typing".. 36 [20:10] <niemeyer> If you've used Python or similar languages before, you know what I mean by that.. 37 [20:10] <niemeyer> In Python, you just provide a value to a function, say, and expect that the function will handle it correctly 38 [20:11] <niemeyer> So any method that has, say, a read( ) method, can be provided to a method that calls value.read() 39 [20:11] <niemeyer> In Go, there are interfaces 40 [20:11] <niemeyer> But they're not like interfaces in languages like Java, for instance 41 [20:11] <niemeyer> if you declare an interface like this: 42 [20:11] <niemeyer> type Validator interface { IsValid() bool } 43 [20:12] <niemeyer> You can use that to declare a function.. 44 [20:12] <niemeyer> func MyF(v Validator) { println(v.IsValid()) } 45 [20:12] <niemeyer> and any objects at all that define such a method can be used 46 [20:12] <niemeyer> they don't have to _declare_ that they implement the Validator interface.. they simply do as long as they have the right methods 47 [20:13] <niemeyer> ... 48 [20:13] <niemeyer> Anyway 49 [20:13] <niemeyer> That's called structural typing, btw.. if you fancy CS 50 [20:13] <niemeyer> A few other factors of the top of my head.. 51 [20:13] <niemeyer> Go is 52 [20:13] <niemeyer> - Garbage collected 53 [20:14] <niemeyer> - Capable of producing good tracebacks 54 [20:14] <niemeyer> - Debuggable with gdb 55 [20:14] <niemeyer> - Has an easy to use module/package system 56 [20:15] <niemeyer> Hmm.. lots of leavers :) 57 [20:15] <niemeyer> Maybe I should get into some action. 58 [20:15] <niemeyer> Let's get it working then. 59 [20:16] <niemeyer> First thing, you'll need to install the language 60 [20:16] <niemeyer> It's available in Oneiric 61 [20:16] <niemeyer> If you're using an older release, there is a PPA available 62 [20:16] <niemeyer> Supporting down to Lucid 63 [20:16] <niemeyer> sudo add-apt-repository ppa:gophers/go 64 [20:17] <niemeyer> sudo apt-get update 65 [20:17] <niemeyer> sudo apt-get install golang 66 [20:17] <niemeyer> Just the last command for Oneiric 67 [20:17] <niemeyer> Now, let's produce a hello world example.. 68 [20:17] <niemeyer> I'll guide you towards having a sane environment that you can evolve from, rather than just a quick and dirty one 69 [20:18] <niemeyer> So, create a directory: 70 [20:18] <niemeyer> mkdir ~/gopath 71 [20:18] <niemeyer> and export the variable: 72 [20:18] <niemeyer> export GOPATH=~/gopath 73 [20:18] <niemeyer> This instructs goinstall that you want to be using that directory for installing programs and packages 74 [20:19] <niemeyer> Now, let's create a source directory for our program 75 [20:19] <niemeyer> mkdir -p ~/gopath/src/example.com/mycmd 76 [20:19] <niemeyer> cd ~/gopath/src/example.com/mycmd 77 [20:20] <niemeyer> When you host your source code, you'll have only that last bit withing the revision control, usually 78 [20:20] <niemeyer> the example.com is just namespacing the import.. it'll become more clear as we go on 79 [20:21] <niemeyer> So, you're now within that directory 80 [20:21] <niemeyer> Let's type the following on that file (on the fly! ugh) 81 [20:21] <niemeyer> package main 82 [20:21] <niemeyer> import "fmt" 83 [20:21] <niemeyer> func main() { 84 [20:21] <niemeyer> fmt.Printf("Hello world\n") 85 [20:21] <niemeyer> } 86 [20:21] <niemeyer> Put that within a main.go file 87 [20:22] <niemeyer> The name is actually not important 88 [20:22] <niemeyer> Now, if you type this command: 89 [20:22] <niemeyer> goinstall example.com/mycmd 90 [20:22] <niemeyer> You should get mycmd within ~/gopath/bin/mycmd 91 [20:22] <niemeyer> Try to execute it 92 [20:23] <niemeyer> Congratulations! 93 [20:23] <niemeyer> You've just run your first Go program :-) 94 [20:23] <niemeyer> Let's go a bit further to understand what we're doing 95 [20:23] <niemeyer> Still within ~/gopath/example.com/mycmd 96 [20:24] <niemeyer> Let's create a second file called util.go 97 [20:24] <niemeyer> and type this within it: 98 [20:24] <niemeyer> package main 99 [20:24] <niemeyer> func Hello() { 100 [20:24] <niemeyer> println("Hello there!") 101 [20:24] <niemeyer> } 102 [20:25] <niemeyer> Now, edit your main.go, and replace the Printf(...) with this: 103 [20:25] <niemeyer> Hello() 104 [20:25] <niemeyer> and try the command again: 105 [20:25] <niemeyer> goinstall example.com/mycmd 106 [20:26] <niemeyer> You'll get an error regarding "fmt" not used.. simply remove the line import "fmt".. 107 [20:26] <niemeyer> and try again 108 [20:26] <niemeyer> Anyway.. the point I'm trying to make is this: 109 [20:26] <niemeyer> All files within a single package in Go are part of the same namespace 110 [20:27] <niemeyer> You can name files as you wish 111 [20:27] <niemeyer> They're just organizational 112 [20:27] <niemeyer> Now, let's get a bit fancier.. 113 [20:27] <niemeyer> Let's introduce a package 114 [20:27] <niemeyer> Later we'll be playing with concurrency a bit too.. 115 [20:28] <niemeyer> So.. let's create our package directory 116 [20:28] <niemeyer> mkdir -p ~/gopath/src/example.com/mypkg 117 [20:28] <niemeyer> cd ~/gopath/src/example.com/mypkg 118 [20:28] <niemeyer> Again, same idea 119 [20:28] <niemeyer> Files are just for organization.. 120 [20:28] <niemeyer> Let's name ours as hello.go 121 [20:29] <niemeyer> Open hello.go within mypkg and put this content there: 122 [20:29] <niemeyer> package mypkg 123 [20:29] <niemeyer> func Hello(ch chan string) { 124 [20:30] <niemeyer> println("Hello", <-ch) 125 [20:30] <niemeyer> println("Hi as well", <-ch) 126 [20:30] <niemeyer> } 127 [20:30] <niemeyer> Let me copy & past locally to follow 128 [20:31] <niemeyer> Alright.. 129 [20:31] <niemeyer> We have a package! 130 [20:31] <niemeyer> One very interesting detail: 131 [20:31] <niemeyer> This package is within its own namespace.. 132 [20:32] <niemeyer> We can only access Hello() because it starts with a capital cased letter 133 [20:32] <niemeyer> This is the way Go differentiates private from exported variables, constants, functions, methods, etc 134 [20:32] <niemeyer> In all of those cases, capital case == exported 135 [20:32] <niemeyer> At first this feels a bit strange, but it has a pretty interesting consequence: 136 [20:33] <niemeyer> Every _usage_ of any of those things makes it clear if what's being used is public or not 137 [20:33] <niemeyer> So.. let's go.. 138 [20:33] <niemeyer> Go back to our command 139 [20:33] <niemeyer> cd ~/gopath/example.com/mycmd 140 [20:33] <niemeyer> And type this new code in there: 141 [20:33] <niemeyer> Within file main.go, that is: 142 [20:33] <niemeyer> package main 143 [20:34] <niemeyer> import "example.com/mypkg" 144 [20:34] <niemeyer> func main() { 145 [20:34] <niemeyer> ch := make(chan string) 146 [20:35] <niemeyer> go mypkg.Hello(ch) 147 [20:35] <niemeyer> ch <- "Joe" 148 [20:35] <niemeyer> ch <- "Bob" 149 [20:35] <niemeyer> } 150 [20:35] <niemeyer> If I didn't screw up, you can run this now: 151 [20:36] <niemeyer> goinstall example.com/mycmd 152 [20:36] <niemeyer> and then 153 [20:36] <niemeyer> ~/gopath/bin/mycmd 154 [20:36] <niemeyer> Try that out 155 [20:37] <niemeyer> I made a mistake, which I'll mention in a bit, but first let's go over what just happened 156 [20:37] <niemeyer> We imported the package "example.com/mypkg" 157 [20:38] <niemeyer> This causes goinstall to look for this package, *download* it if necessary, compile, and install it 158 [20:38] <niemeyer> You can check that this is indeed the case by listing: ls ~/gopath/pkg/*/* 159 [20:39] <niemeyer> You should get a mypkg.a inside it 160 [20:39] <niemeyer> This is your package example.com/mypkg compiled into binary form 161 [20:40] <niemeyer> Then, we've called the Hello() function within it 162 [20:40] <niemeyer> But we haven't simply called it 163 [20:40] <niemeyer> The "go" keyword we've used ahead of the function call instructs the compiler that the function call should be put in the background 164 [20:40] <niemeyer> So mypkg.Hello() was running concurrently with your main() function 165 [20:41] <niemeyer> Then the statement 166 [20:41] <niemeyer> println(..., <-ch) 167 [20:41] <niemeyer> Will block in the channel receive expression (<-ch) before a value is available for consumption 168 [20:41] <niemeyer> which is exactly what we did next in main() 169 [20:41] <niemeyer> ch <- "Joe" sends a value 170 [20:42] <niemeyer> The mistake I made in that case, is that the main() function is not waiting for the concurrently running function to terminate 171 [20:42] <niemeyer> There are tricks that may be used for this, such as 172 [20:42] <niemeyer> select{} 173 [20:43] <niemeyer> Then, in case you wanted to actually publish that code to be easily consumable, 174 [20:43] <niemeyer> you could put the code within Launchpad or Github 175 [20:43] <niemeyer> Exactly as it is 176 [20:43] <niemeyer> Just put the content of "mypkg" for instance within the trunk of a project launchpad.net/mypkg 177 [20:43] <niemeyer> And people will be able to "goinstall launchpad.net/mypkg" 178 [20:44] <niemeyer> So.. that's a quick introduction to the language.. 179 [20:44] <niemeyer> But there's a _lot_ more to talk about it 180 [20:44] <niemeyer> unfortunately I cna't type that fast and we don't have as much time :) 181 [20:44] <niemeyer> So I'll provide some resources 182 [20:44] <niemeyer> And open to questions 183 [20:45] <niemeyer> The main site is the key documentation point: 184 [20:45] <niemeyer> http://golang.org 185 [20:45] <niemeyer> There's _very_ good introductory documentation there.. 186 [20:45] <niemeyer> I recommend the Getting Started, Tutorial, and Effective Go, in that order 187 [20:45] <niemeyer> You should be quite proficient after that 188 [20:45] <niemeyer> Well.. or able to use it at least.. 189 [20:46] <niemeyer> Proficiency comes with practice 190 [20:46] <niemeyer> I'm one of the external contributors of the language as well, so I'll be happy to answer deeper questions which I'm happy to be familiar with in case you have any 191 [20:46] <niemeyer> So, that was it.. please shoot the questions.. 192 [20:47] <niemeyer> Or maybe not.. :-) 193 [20:49] <niemeyer> Alright.. I guess I'm alone in here. :-) 194 [20:49] <niemeyer> Thanks for attending, and please drop me a message if you have questions. 195 [20:50] <niemeyer> #go-nuts in this same server is also a good place to talk about it. 196 [20:50] <niemeyer> I'll be happy to answer questions in the -chat as well 197