>> PIKE: I’m going to talk about the Go Programming Language, which is going to be--we
hope going open source on November 10th, which is in just a couple of weeks. This talk is
a little bit before then, so some--there are some future tense for things like links and
so on, but everything should be as recorded by the time we actually go public with this
stuff. You can see we have a website we’re setting up, which will be the public domain,
public viewable domain for that. So, what is it? Well, I’m can talk about all these
pieces but it is new, an experimental, concurrent, garbage-collected, systems, language. Experimental
because we’re not--we don’t believe this is the answer to everything, but we’re playing
and we think it’s gotten to the point where it’s time we should probably tell the world
about it. It’s concurrent because it’s really important in the modern world. It’s
garbage-collected because we have an opinion on that stuff, which I’ll talk about it
quite a bit later. And it’s a systems language in the sense that we intended to be written,
to be used to write things like Web servers and other, you know, system aspects like that.
You have more control over some things and you have another languages like, say, Java
or Python, but it’s--it works like a systems language when you use it. On the other hand,
it's very good at things we find for things like front-ends or just general programming.
So, although, it’s designed as a systems language, it has much broader use than just
that. I can't give a talk without showing you, "Hello, world." There’s "Hello, world"
with the "world" being Japanese, which I want to attempt to pronounce. But you can see that
it looks vaguely C like although there’s some "weirdnesses" about it. I won’t talk
about what those "weirdnesses" are. Who’s involve? Well, I’m giving the talk but it’s
by no means my project. There’s a bunch of people involve and I want to make sure
everyone’s cleared. Some of the names are really important here. Robert Griesemer, Ken
Thompson, and I started talking about doing something to solve the problems we were seeing
with other environments. Some time around two years ago in late 2007, we played mostly
at the Wade Park for a few months to figure some things out. But by middle of 2008, we
had a toy compiler and things were starting to look interesting and we started working
on the stuff for real. And around that time, Ian Taylor joined and Russ Cox joined, and
the five of us did the most of the work, but we’ve had a lot of help from a lot of people
that this slide is too small to name. So I just make--I want to make it clear this is
a collaborative effort and the collaboration is growing. Why? Well, the reason is things
were just taking too long: too long to compile, too long to build, too long to think about.
We want a program fast. We want a program fun. And to make programming fun, you have
to find ways to speed things up and make things work better, not just the code itself but
the process of writing the code needs to be efficient. So what’s happened? Well, you
know, program used to be fun. What went wrong? Well, it’s interesting there's been really
been no new major systems language in at least 10 years or could be longer. But in that decade,
a lot has changed. The libraries have gotten bigger. Professional programming has, to a
larger extent, become a layering process, and so we layer more and more stuff on and
we also broaden out the base. The libraries got really big. There’s a lots of them.
They communicate with dependencies to one another and so the force has become a thicket,
and at some times it’s kind of hard to cut your way through it. Networking has pretty
much taken over the world, that's the way to think about computing. The old son thing
about the network is the computer is pretty much true today, but the languages don’t
really reflect that. There’s a lot of client/server kind of stuff especially in the systems base.
Languages don’t really help you there too directly. Of course, we’re talking about
massive compute clusters now and again, the languages are designed for single processors.
They don’t really work very well in that model. And on a related note, multi-core CPUs
are taking over, too. It’s getting harder to buy a high-end computer with only one processor.
It tends to be multi-core, sometimes multi-chip/multi-core. And again, the languages that we’re using
weren't really designed with that kind of stuff in mind. And it’s also gotten--I think
this is the thing that finally pushed us to try to do something. It’s just gotten to
slow to build software. The tools are slow. They have a hard problem to do, but they still--they’re
tend to be slow and they’re getting slower. The computers have speed up enormously but
the software development process, if anything, has gotten slower over the last ten years.
The dependencies are uncontrolled and the languages don’t help you control them, so
you tend to spend a lot of time maybe building things you don’t even need but you don’t
know it, can’t prove it. The machines have also stopped getting faster. They’ve gotten
more but they haven’t gotten faster. There are more processors, there are more of them,
but the actual clock speed has hardly changed in the last few years and Moore's law, to
some extent, is peering out and yet the software gets bigger and bigger and bigger. And so,
somehow, it feels like if we don’t do something, then software construction is just going to
become unbearably slower and we need to think about the process of making it fast again.
Robert Griesemer observes that a lot of the interesting work in languages in the last
few years is been because a lot of the people using these standards systems languages like
C, C++, even Java are finding the clamp--the type systems are very sort of clumsy or hard
to work with. And as they go to the dynamic languages: the Pythons, the Ruby’s, even
the JavaScript of the world, they have a lot more fun because the type systems don’t
get in the way so much at least as long as the program keeps running. And so, the challenge
here is to try to deal with this. You want typing. You want a good typing because it
makes programs robust, but it can be done badly. And we are given in some ways, there
is--if not done badly, it should at least be done the different way. Sometimes good
ideas, in principle, make bad practice. And a good example of that is the "const" keyword
in C and in C++, which was very well intentioned and seem to address the real need in making
program safer, but it tends to make programming awkward in a lot of ways, so this isn’t
worth the benefit you get back from using. Also, there is this notion of everything being
a type hierarchy in object-oriented programming. And yet, the types in large programs don’t
really naturally fall into hierarchies. We find the way to make them fit, but it’s
a bit of a struggle. In program, we spend so much time re-factoring a code, juggling
type trees around, and that has very little to do with the implementation and lot to do
with the way the language is forcing you to think. We’d like to be--we’d like to sort
of step back from that model. And in short, therefore, with the way type systems work
today, you can be productive or you can safe, but you can’t really be both. And that seems
like a shame; we should be able to fix that. So, why a new language? Why don't we just,
you know, fix what we've got? Well, some of the problems are just fundamental to the way
the languages are thinking, the way the type systems work, the way they’re compiled,
the way dependencies are managed. The languages themselves have these problems endemic in
them, and to fix them, you have to rethink the languages itself. For instance, the libraries
can’t help you, because adding anything to try to fix some of these problems is going
in the wrong direction. There’s too much already. We need to trim down, cut the fat,
and make things cleaner. Fixing it by adding software isn’t going to do it. You have
to sort of step aside and do something separate. And so, we decided: Robert, Ken, and I couple
of years ago that we need to start over. Just take a step away and think about the way programs
are written and constructed and try to make a language that makes that process a lot easier.
So, it’s a new language. What are the goals of this language? The sort of short version
of the story is we want the efficiency of a statically compiled language; that means
truly compiled language, but the ease of programming of a dynamic language. And I think we have
come pretty close to achieving that. You can decide for yourself as we go on. Safety is
critical. It’s critical to the language: the type-safe and then the memory-safe. It’s
important that a program not be able to derive a bad address and just use it, that a program
that compiles is type-safe and memory-safe. That’s a critical part of making robust
software and we just--that’s just fundamental. We want good support for concurrency. I’ll
talk a little bit about that. Communication, I’ll talk about that, too. Those are tools
that can help you build software that runs in the network or in multi-core CPUs. We want
to build--we’re going to garbage like to think, because a lot of the bookkeeping that
goes on inside modern programming, especially in C and C++, has to do with memory management.
And that can be totally automated. And we believe, "believe" is the word, that you can
do that efficiently and, essentially, latency-free that the garbage collection technology is
advance to the point where a garbage collected systems language actually makes a lot of sense,
and so we’d like to do that. And also, we’d like the compiler to just run fast. Everyone
knows this slide and there’s some truth to it. You know, you spent too much time waiting
for compilers. So, let me give you a compilation demo here. This is a directory of Go code. If you look
in here, there’s a 1,300 lines, so I make clean, and then I’ll just do a major. There,
I just built the last library. That’s compiled, efficient code, clean again. In case you wonder
if I can type, okay, time make. Okay. So that’s what two--well, pretty accurately, 200 milliseconds
real time to build the library. That feels about right. For the last years or so, those
who’s working with Go had been getting used to 100 millisecond builds on one machine.
That’s running on my laptop, by the way. That’s not some distributed thing. That’s
one processor, one build. And just to prove it a little better, let me make clean. This
is the complete Go source tree. All of the libraries written in Go, there’s something
of order. I think it’s about 120, 130,000 lines. So, included in here are regular expressions,
flags, concurrency primitives, the run-time, the garbage collector, pieces--oh it’s finished.
Okay. So that was a one processor. I could’ve paralyzed it a bit better. But that’s eight
seconds. That feels long to me now. That’s a long time because this is all the software
that’s there and, you know, it’s a long time to build--you can get a lot done with
that much time. Just to remind you, then we go back here, that’s what you want to see.
You want to have character return time for your compilations, and it can be done. So
let me get that set for later and we’ll go back to this. Okay. So, we think we’ve
got fast compilation and I can’t tell you how much--what a difference that makes to
your life. Sometimes hours and hours to go by when people finally showed up to my office
and say, "Hey, you didn’t answer my mail." I have to look in the mail and actually getting
work done. Okay. So to do this language, we had to have some principles on which is built.
And there are actually some fundamental principles in here that in some ways, I think, differ
from some of the other languages out there, so I'd like to go through them. One of them
is that we try as much as possible to keep the concepts orthogonal. For instance, in
the interface surface, I’ll talk about the concept of implementation versus interface
or completely orthogonal. They’re two separate things, they don’t interact and you don’t
define them together, you define them in separate objects and that makes a lot of stuff cleaner.
And in practice, this is because a few orthogonal features that cover the space work a lot better
in practice than a lot of overlapping lines. That’s a principle that’s a little vague
but I think, I think you know what I’m getting at. The grammar is very regular and very simple.
It’s actually conflict free and can be parsed without a symbol table, there’s no conflicts
in it. That makes it easier to write tools, like IDEs or editor plug-ins, and things like
that, debuggers because the parsing line is understanding and the program is actually
pretty straight forward. We try to reduce the typing. What I mean by that is that we
want the language to work things out. You tend to type too much when you’re programming
in modern object or in languages. You tend to write statements like that. That’s literal.
If you change "Foo" for a much longer word, that’s an example I found in some code I
want to end. And I just, you know, "Foo" should just go away. You shouldn’t have to type
all those "Foos," that’s crazy. So you want to get rid of the bookkeeping, you want the
type system to automatically works the "Foo," but you still want to be safe. You want it--you
want it to be type-safe, but well handled. And also, not only you don't want to reduce
typing, you want to reduce typing. You want to type to sort of melt away into the background.
You want it to be clear, you don’t want to type hierarchy, we don’t want to type
hierarchy, and then I'll show you some examples on why that actually helps. We just think
the program by constructing type hierarchies, is not the way to go. We have an alternate
world. However, Go is a profoundly object-oriented language. Arguably, more object-oriented language--more
object-oriented than, say, Java or C++, and I’ll show you why. So, the big picture,
there’s some fundamentals. We have a clean concise syntax. We have very lightweight type
system. We got rid of implicit conversions, because they’re all inconvenient. They tend
to cause a lot of confusion particularly in the old C rules for things like the, you know,
the usual conversions are actually not all that usual, and now these got right. So everything
is very clear and very clean on what’s going on in the page. Of course, when you know the
conversions, you tend to do a lot of casting or conversions by hand and that’s messy,
so we address that by changing constants pretty profoundly. I’ll talk about that in a little
bit. You'll never--you won’t see "0x80ULL" in a Go program. The ULL is completely pointless,
you can’t even say it, numbers are just numbers. And there’s a strict separation
between the interface and implementation. That’s part of keeping the concept orthogonal
and the type system clean. So there’s a runtime, there’s a garbage collection, there’s
a good support for strings, maps, associate raise, that kind of thing, and also the communication
channels, which we’ll talk about, and then there’s really strong support for concurrency.
It’s actually some of the best concurrency stuff, I think, that’s out there. It's really
good. And then, there’s a package model, which I won’t talk very much about because
it’s kind of takes a lot of explaining. But the notion here is that inside the packages,
everything is explicit. What you depend on is explicit. Compiler rejects your program
if you put in the dependency you don’t need. It’s all very clean and so, it makes tools
easy to understand dependencies and then it makes the builds guaranteed minimal. So, that
helps enormously. Regarding the dependencies, the linking going faster, the compilation
can go faster but--and there’s actually a notion in here that I think is important.
The compiler actually pulls the transitive dependency information up the tree as it’s
compiling, simply to reduce the number of files it has to look at, which in turn speeds
up the compilation process. So, if you have a program, A.go, that depends on B.go that
depends on C.go, which is pretty standard kind of thing. You--in the usual way, you
have to compile them in reverse order, because you got to build the dependent stuff before
the depending stuff. But the point is when you go to compile, A.go, it doesn’t need
to compile C. It doesn’t need to look at C.go at all. It doesn’t even need to look
at the object code for C, because everything that B need from C has already been pulled
up into B.go. And that doesn’t sound like a big deal, but when you’re at scale, it’s,
literally, exponentially faster at building software when you get in to this huge dependents
situation. For concurrency, we sort of have a model. I’ll touch on it today. There’s
a lot more stuff online about it. But we have a suggestion for how to write systems and
servers as concurrent garbage-collected processes, which we called, goroutines. We’ll have
good support from the language and the run-time. We change the name because they're slightly
different from what you're used to. If you use the words like thread or process or goroutine,
that’s not quite the same, so we have our own word, goroutine. The language takes care
of managing the goroutines and managing the memory that they use and the communication
between them. Stacks grow automatically. That’s taken care of by the language. You don't have
to declare how big the stack is going to be. If it needs a bigger stack, it gets the bigger
stack. If it needs a smaller stack, it uses less memory. And those stacks are multiple--I’m
sorry, the goroutines are then multiplexed on the threads. That’s all done automatically
for you and [INDISTINCT] transparently. And, one of the feature--one of the reasons for
needing garbage collection is that concurrent programming is very hard without garbage collection,
because as you hand items around between this concurrent things, who owns the memory? Whose
job is it to free it? And there’s a lot of bookkeeping involved that the--if the language
or the system doesn’t take care of that for you. So you need garbage collection to
make concurrency work well. On the other hand, you need--to get the garbage collection to
work well, you need a language that makes garbage collection a feasible thing to do,
which is another argument for doing a new language. So, I don’t have time to explain
all of Go to you. It’s a significant language, it’s--I’d say probably bigger than C but
not as big as C++. Enough time to go through all of it, but I want to give you the flavors.
I’m going to go through about a dozen slides that are--I hope sort of representative of
the kinds of things that go on, but I’m going to leave out quite a bit. Lexically,
it looks a little bit like C, actually a little more than like C than this slide, we let you
believe. There’s usually a keywords involved, introducing things, you see const and var.
Const, that means it’s a constant, not--it’s not the const keyword from C, it’s completely
different meaning. It just means, in the first line there, N is a constant 1024. And it’s
just a number, it’s not an int, it’s not a float, it’s not an unsigned int, it’s
just a number. And there’s a const string and you can see we support Unicode just fine.
In fact, the language requires that the input be UTF-8 encoded. And then, you can declare
variables with the "var" keyword in the usual way. You’ll notice--I’m quite use to it
now, but for C programmers this looks backwards, because in C, you put the float before the
X and the Y, but they're reversed and there’s a long explanation on the web about why we
did this. But the fundamental reason is it actually has been cleaner because, for instance,
in that declaration, X and Y both have type float. Whereas, if flip it around put the
keyword first, things get a little funnier. And you can see what the C version of that
will look like. You'd have to reproduce the star. So this is simplification you get. There’s
characters, Unicode supports, and stuff like that. Then we in this example, was not really
an example, just some lines of code, there’s a type struct, T, that's defined. It's got
a couple of fields within if they're both integers. Then we declare a variable, t0,
which is a new T. That should be pretty familiar what that means. But there’s too much typing
going on there. So the next line there, T1 := new(T), that’s an old notation from some
languages that I work with before. What that call and equals means is declaring the initialized.
So that--those two lines are equivalent. Var t0 *T = new(T), it has too many Ts in it.
We can get rid one of them by just having the type of t1 we derive from the expression
that’s used to declare and initialize it. And you’ll see that used a lot in Go code.
The var doesn’t show up nearly as much as the colon equals notation. Their control structure
is they're actually quite interesting control structures--just the first blast through,
pretty the same as C. They’re actually quite richer, but the basics are the same. The main
difference is syntactic. The braces are required on the blocks and there’s no parenthesis
on, for instance, the conditional expression inside an "if" statement. That's just to clean
up the grammar. So here’s a real program. It’s not "hello, world," it's echo this
time, but it’s got all the parts. The first time the code says, "package main," that has
some meaning in the language about me get muted. We're thinking about simplifying a
few things but at least for the moment it's "package main." then you can see there's a
function called "main" is declared down below. And the program begins execution by starting
"main.main" initialization inside. There’s a declaration of the flag from the flag’s
package, so that makes minus N, turn off new lines from echo. It’s not strictly a UNIX
echo because it’s got real flag parsing, but it’s essentially the same. Those import
statements say, "We’re going to use package OS," which does some stuff for us and we’re
going to use the flag package, obviously. Now, the way the initialization stuff works
is that in-flag variable will be initialized before "main" starts executing. All the global
variables get initialized by--and they can be initialized by arbitrary complex stuff
before "main" starts. So then in "main," we do the flag parts that get the command line
pulled apart. And then we just loop over the arguments which are now the [INDISTINCT] the
flag package, and it’s the obvious loop accumulating. You can see += on the string
there to append to the string, and stuff like that. And then at the bottom, the flags are
actually pointers in Go, the flag package makes them pointers. So the *nFlag, which
is a Boolean, is false. Then, you add a new line to the end of it. And then finally, you
do a method called "os.Stdout" to get the open-up. So, although, pretty much every line
in here is different from what you’ve seen before, it should be perfect and clear what’s
going on. I don’t think you’ll find that a mysterious program. So let’s talk about
constants. I said they are a little different. Constants in Go are what we like to think
of as sort of type-less. They have no type. They have no size. They’re just numbers
or strings. You can have constants and strings in Booleans, but numbers are the interesting
case. So in this little snippet here, is just some constants being used. We start by defining
a type TZ for timeZone, which is an integer. And then, we declare some constants, UTC and
EST. We declare them to have type TZ and assigned to those initial values. You can clear what’s
going on there. The parenthesis around the const is distributing the const declaration
introducing keyword across the elements inside that declaration. So that’s the same as
saying, "Two const declarations with the two variables in them." You’ll see later on
the next page here that actually matters that you can group them like this, because there’s
a thing called iota, which is an enumerating constant. It literally--for each const declaration,
counts which element you’re on. At every semicolon, it increments. Starts at zero on
the next line, it's one, the next line is two. And so, here you can see, we’re declaring
bit0 and mask0 to be uint32s, and the first one is set to one shifted up iota. Iota starts
at zero in every const. So that’s one shifted up zero and one shift zero minus one. So that’s
a bit and a mask. And then the next line does it again, but now iota has gone up to one.
So we get the next guy in the sequence. You can see how to use that to build enumerated
constants but this is a slightly richer example. And again, to reduce typing, if you want,
you can just say, declaration, like the third line there with the semicolon and what that
says is, "Just keep doing what I did." Take the declaration initializer from the previous
line then pretend that you just type that here. And so, if you want to declare a new
ready constant, you can say, const open parenthesis inum0 equals iota semicolon and then you just
go inum1 semicolon, inum2 semicolon and all the way down the page. And just have them
declare sequential numbers for their constants. One very important properties of these numeric
constants in Go, is it there are arbitrary precision. So, here’s a const, the logarithm
of 2, you can see that’s got like 40 or 50 decimal places in it, which is more than
even a float 64 can represent. But that’s a valid declaration, because they’re just
numbers. And then the next line, we can actually compute log2, log base 2 of E as one over
log of 2, and that’s a precise division because it’s happening not in floating point
space but in arbitrary number precision space. So that’s a very accurate reciprocal. And
that kind of stuff is nice too, because you don’t see cache and conversions and worries
about overflows and underflows. Constants just take the job for you. And then we have
values, obviously. There’s an array like type called the slice. Those are arrays but
they’re kind of peculiar. You don’t use them much. Instead, use a reference type called
the slice. So we can there, is declared to be a slice of strings with Saturday and Sunday
as strings declared inside it. And then we take the timeZones and make declare timeZones
map to be a map from a string to TZ or timeZone. And you can see how that works. It’s pretty
straightforward. There’s a function declaration to do an "add." You can see the function syntax
there. There’s actually a lot of interesting things in how functions deal with return values,
which I’m not going to talk about today, but you should check that out. And then, there’s
a declaration of function type which takes two integers return int, so "add" is of type
Op. And then, here we declare an RPC, which is a structure. I showed that before but it's
a [INDISTINCT] example. It’s got A and B integers. It’s got an operator, and it’s
got a result which is a pointer to an integer. And all that should be fairly straightforward
even if the declarations look backwards to a C programmer. And then the last line there,
we declare using a structure literal, an instance of an RPC and again, it’s very simple. You
just say type name, open brace, list the elements of the structure, closing brace and then you
got a value, you can assign that to or in this case, initialize a new variable to that
value. So, I said [INDISTINCT] language. We haven’t seen much yet, there was actually
one and the other is a method in the echo example where we wrote the os.Stdout. But
let’s talk about methods, because they’re kind of different. So here’s a type called
point that has X and Y. Now, those are upper case and the reason is, in Go, the complete
decision about whether an identifier is visible outside the package or not, is whether or
not it starts with an uppercase Unicode letter. That’s it. So if a variable or a type or
whatever declared at the top level is uppercase, is visible to the clients of the package.
If it’s lower case, it’s not. Inside the global struct, if a method or field is uppercase,
it’s visible to the clients of the package, otherwise, it’s not. That’s it. It’s
really simple. So, there’s that type. Now, we’re going to define a couple of methods
on it. The declaration syntax for a method, you’ll notice it’s not declared inside
the struct, and the reason, we'll see in a minute, is a method and structs are independent
ideas. You can have methods on things other than structs, so it wouldn’t make sense
if you put them inside the struct declaration. What you do is you say, "Here’s a func."
And then before the name of the method, you write a parenthesis, kind of like its own
little one element parameter list, receive a declaration and receiver is a short hand
for the thing that’s receiving the method when it’s called. So this says, that scale
is a method of type star point and it takes a float argument and then the implementation
is inside and it’s just multiplies up the point by the usual, by the scale factor. You’ll
notice that the receiver is explicit. There’s no this, automatic or anything like that.
You have to actually say, declare receiver and use it if you need to access the fields
of the struct inside the method. And then there’s Abs, you can imagine what that is.
There’s a square root, which is a function inside the math package computing the hypotenuse
of the point of the [INDISTINCT] of the vector. And then here’s--we declare an X. Now, this
time you notice there’s an ampersand before the point, word there. Point of three, four
is a value. Ampersand of point of three, four allocates. It’s like a constructor like
thing to create a pointer to a new instance of that. And that--every time you execute
that, you get a new instance of point that initializes the three, four. Then, you can
call x.Scale, which is assumed you'd expect to be able to do. Okay. So that’s pretty
simple. The syntax is slightly different, but the ideas are pretty simple. Now, it gets
more interesting because methods on any type you define. And here’s a full example, this
is another complete program that actually does something a little different. So again,
we start with package main and now we import fmt, which is the formative printing package.
It has printf and stuff like that in it. And then, here’s our type TZ int coming back.
And now, we declare few more of these constants, we have an Hour which is of type TZ, which
is 60 minutes times 60 seconds. And then we declared, just to make it short, two timeZones:
Zero hours and minus five hours for UTZ and EST, okay? Now, we declare a map from the
names to the values of those timeZones. That should be familiar in the timeZones. We actually
have that exact the same example before. And now, we put a method on a timeZone. Now, timeZone
is just an int, but I’m going to put a method on it. So, I declare a function called capital
string that returns a string to receive tz, lower case, plus a type TZ, upper case. Notice
that it’s not a pointer, that’s really important. It doesn’t have to be a pointer.
And then, using a variant of the for-loop that's arranged over the elements of a collection,
I say name comma zone is range of timeZones. What I’m looking for is the element of the
timeZone map whose value is equal to the value of TZ. That’s the name of the guy I want.
So it’s like reversing the map. So I just loop over all the elements looking for the
one whose timeZone is equal to the zone of that element of the map and if that’s true
I return the name. And you can see there’s actually quite a bit going on in there. There’s
the range which is giving you the iterator, there’s a cone [PH] equals to declare loop
variables that work over the elements and thing inside in and all not. But of course
you might get a value of the--of TZ integer that’s not an exact timeZone number. And
so, if that happens, we finish the loop and we return fmt.Sprintf of blah-blah. An Sprintf
is analogous to the standard C as printf, but actually returns a new string. It doesn’t
put into a buffer. So, that’s an implementation of a method that let’s you print timeZones
in interesting ways. So we can use it in our main function by saying, if we just say, fmt.Println
of EST, Println is a variant of print that doesn’t require a format. It’ll work.
It’ll actually printout EST by catching it in the inner loop of the string method.
And notice that Println(EST) knows under the covers by mechanisms that are described the
length and the website, how that the timeZone type has a string method and that’s how
you should pretty print it if you get a value of that type. So, that’s all you need to
do to make it print itself. And then, there’s another example, we can print Println five
times hour over two and it comes out as plus two colon thirty, because the printf at the
bottom works. So this is a fairly contrive example, but you can see to there’s a [INDISTINCT]
going on here. Having methods on general types, as any small talk programmer will know, a
very convenient thing to do. But by separating them methods away from structural classes,
we actually introduce some new ideas that you can play with and that’s pretty fun.
Okay. So now, we come to something that I will not be able to describe in full in the
time available, but they are pretty interesting and they are arguably the most noble about
Go, and that is the concept of an Interface. An Interface is an, what’s the word, a formalization
of the concept of a set of methods. So, we can declare a method, sorry, an interface
type Magnitude and say that anything that implements the Magnitude interface is something
that implements the Abs method that returns a float. And of course there could be lots
of other things in there, but we’ll assume for the moment there’s just one. So, remember
we declared an Abs method for the type star point. So, we can--we had an x from the previous
slide, we go back there, there, that x address the point three, four, that’s the same x.
We can use it here. We declare a variable with the interface type magnitude and assign
it to assign to it the value x. And the reason we can do that is x is an implementation of
that interface, and so that’s a valid assignment, okay? And having done that, had I typed var
m magnitude instead of m magnitude. No, I got it right. Sorry, sorry, I confused myself.
Var m magnitude is a variable, we assign to x and then we declare a new variable mag that’s
m.Abs, so it’s just the, the vector length of the point x. But now we declare another
type point three which has three coordinates to find the Abs method for that, same idea.
And now, we can assign m equal to a point three and that value still is an interface
var, but inside it is an object that has the implementation of the Abs method. And so we
can call the Abs method on that and add that to the variable that we’ve got. And then
we can do it again, and this time just to be fun, we declare a polar object, which is
R and theta and, of course, that’s a capital theta because a public field. And then, we
declare p Polar. Notice there is not a pointer this time. Why make it a pointer, it doesn’t
matter. So we just make it a value polar and it returns the radius of the thing which is
the definition of the magnitude. And then we design a value that type to m, and now
we can add another thing at the magnitude. So the interface variable is letting you define,
"I can work with anything that implements these methods and anything at all will do."
Here, I use three different representations of a coordinate, but they’re quite different
in character. Under the covers, it’s all very simple. And the key point is that nowhere
does point three or polar have to tell you that it implements the magnitude interface.
It implemented the fact, though, because it satisfies the methods that are defined by
the interface. And there’s way more going on there than I have time to talk about, but
I have to talk about one and very important concept behind them, which is the generality
that they give you, because any method, it could be part of an interface, an interface
can be any method. It's all sort of, it’s not one to one, it’s many to many. It’s
all mixed up. And so a struct of a given type may implement multiple interfaces depending
on what interface you are using. And that gives you the opportunity to define very simple
interfaces that define very general properties. And a really good example of this is in the
IO package and it is called the Writer interface. And a Writer is anything that implements a
standard write call and that’s what we define a standard write call to be. The, you know,
there’s a slice of bytes that can--that is the data you’re going to write. It has
a length inclusively inside it, so we don’t need a byte count. And it returns, there’s
that function that [INDISTINCT] before returns a pair, a count and an error, but don’t
worry about that. Just think about the writer. The writer said anything that implements this
standard form of the write call can be used to write it to. It makes sense. This is just--it's
almost a tautology. But now, anything you implement write for can be used by anybody
that only needs something that implements write. It doesn’t matter where the properties
it has. So for instance, fmt.Printf which is just what it sounds, fmt.Fprintf, pardon
me, which is product much what it sounds like, doesn’t take a file as the first argument.
It takes an io.Writer as its first argument. And a result, you can call fmt.Fprintf on
a network connection, a pipe, a file descriptor, a buffer, all kinds of other things, anything
that implements write, a cryptography pipeline. And then, the way buffer io is done in Go
is that there is no such thing as buffer io, there’s just buffering. And what happens
is if you want to create a buffered version of something, you give it a writer which is
anything that implements write into the covers and it gives you back a buffered version of
that same thing that you can use where you used it before. So here’s an example that
puts that together, again, a complete program. Starting with package main, we import bufio,
fmt and os again. And now, we wrote the os.Stdout before, but now were going to use Fprintf
to write to it to make it explicit. So, we say, fmt.Fprnintf os.Stdout hello. Then, we
call bufio.NewWriter. We pass it os.Stdout but NewWriter only--all it cares about os.Stdout
is that it implements the right call. And the NewWriter function inside bufio returns
something else that implements the writer interface, and so I can write to it. So, I
can call fmt.Fprintf of buf and now I have a buffered write. So I better flush it when
I’m done. But you see the Fprintf use two different types in there for its output and
it worked, because underneath--if you look at the Fprintf declaration, all it cares about
is that the thing that is being passed in implements the write call, which of course
they do and it’s type checks, so you know they do. So, there's a lot more of that stuff
to talk about to, but we’re trying to skip through the highlights. Communication channels
are little as radical than Interfaces because they’re based on, worked on in some early
language, going back to a Hoare’s CSP. But unlike Hoare’s original CSP, the communication
is done through first-class values called Channels. His second round of it done about
10 years later had these, but we’d played with them linguistically by then. And, the
ideas, you make a Channel, it has type string. That means you can send and receive strings
on that channel. Just like a pipe that you can send type values through. And so, that
notation with the left facing out is the communication operator when you used infix it means send.
So, that sends the string, hello, down the channel. And somewhere else, some other time,
some other Goroutine can do read from channel c by doing a prefix operator on c of that
communications and get out the greetings, so it will see greeting as assigned to hello.
And this is haven’t done giving Goroutine because the channel is synchronized by default,
hello. You can control that when you allocate them. And one of the cool things about having
them is you can make them--channels can actually be first class size. That means you can pass
a channel on a channel. And I’ll show you in a minute to actually give you some interesting
capability. So, if you have someone else wants to have this channel that you can send greetings
on, you can pass it to him over channel then he can send you greetings, all right? So,
to do that, though, we have to talk a little bit about Goroutines. So, I’ve mentioned
some calculations, it just takes far too long, right? Who wants to wait around for that?
You're going to block forever waiting for the calculation, but maybe you don’t want
to. What you can do instead is create a channel to get the answer back on. And then declare
a function, wrapper, that takes the value of the parameter for the calculation, and
a channel invokes the calculation and then when it is done, sends the result back. And
I broke it in two lines just to make it easier to read. You'd probably just write C gets
long calculation of A in a real code, okay? And then, to run the thing, there’s a Go
keyword. Go is a keyword. Go wrapper of 17c says, "Take the function call, 17 comma C,
and run in the background and let me keep going." Okay? And then, eventually, you want
to hear what happened, so once you’re finished doing your business, you come back and say,
"Okay, I’m ready for the answer now." And you say, "Now, I want to receive from C and
get the result." So I’ve taken this calculation and I’ve solved it off over here and then
it slows back to me by doing a receive on the channel down underneath. That should be
fairly easy to follow. This might not be so easy, but we’ll try. This is a multiplexed
server. At least, the server side of it, I’ll show you the client on the next slide. And
the idea here, remember I said you can pass a channel to a channel. What we have is a
request which is a request for the server to implement. That's trivial. It just takes
a pair of integers in the channel in which it replies. Very much like what we did before
on previous slides, generalized somewhat. We defined a binary operator type and we defined
a function run that takes a binary operator and a request and sends on the reply channel
inside the request the value of running the operator on the arguments inside the request.
So that’s just turning to send the operations in the sending of the thing from the previous
slide into a function, not very exciting yet. But then, we defined a server function that
takes an operator that is going to serve in a channel of request. And it’s just sits
in a loop reading request from the service channel and then saying run of Op request,
but it puts a Go keyword at the beginning. So, it runs all these requests in parallel
in the background. The server is never blocked. It’s always ready to receive another call
no matter how much is going on. Obviously, there's issues about re-limiting and stuff
like that, but let's not worry about those. The key point is that that’s, basically,
a server loop. And then, to make it easy to use for the client we defined a public function
or an exported function by starting with a capital letter, starts server. And it says,
"Take an operator and start a server for that operator and return the channel on which those
requests can be sent. So, what we do is we allocate the channel, a channel start a request,
we start the server process which in turn is going to start the little implementers
of the operator as they come in. And then, we return the channel as the return value
from start server. So, you call a function you get a channel back, now you got a thing
you can talk to and that is the fundamental idea on how you use this stuff to build services,
okay? So on the client side, it looks like this. You say, server, start server, here's
a function. Now, notice that I’m just writing a function in line there. Go has four closure,
it seems writing down its expressions. And so, now I’ve got a server running that’s
going to add numbers for me. And I’ve got a channel for that server in the variable
server called Lowercase Server. I allocated a couple of request in the obvious way and
inside the request, I allocate new channels because I want to do--respond to me on separate
channels for whatever reason, okay? And then, I can send the request to the server, it doesn’t
matter what order I send them. It’s totally not blocking. I'll just send them anywhere
I want. And now, I can print them out again, print the results as they come back. And I
don’t have to worry about the order because, again, it’s totally parallel. So, in fact,
I send one first but ask her two first. And if two takes forever, I’ll still hang around
there waiting for the response to come back and once it finally does then I’ll print
the value on one even if one is ready sooner. So, this one is very rushed through hear,
so I apologize if I left you a little be fuddled, but there’s examples like this in the tutorial
and some other documents. It should make a little clear what’s going on if that looses
you. Now, if we go back to the server here, remember I said, it has a rate limiting issue
and also the problem is it runs forever. You want to go and shut it down. One way to do
that is to use a control structure in Go called the Select, which is quite a rich control
structure. But the basic idea is given a set of communications on channels. Select let’s
you choose, let's you to actually wait for any one of them to be become ready and once
it does become ready, let that single thing communicate. So, it’s like a switch statement
for communication. So, if we replace the inner loop of server, which was just, remember,
get a request and then run Go on it. With an operator that has a select statement inside
it and the second channel called Quit, that’s passed into the server when we create it.
Then, we can just run this normally. It will just do what it was doing before, but as soon
as you want it to go away, we just send a signal by sending a Boolean of any value,
it doesn’t matter what, on the Quit channel and that branch of the select will fire and
this function will return, which is equivalent to exiting the Go routine. So, that’s again
pretty quick and I apologize for that. But I want to make sure we hit some of those points.
And in fact, there’s a lot more to talk about. I haven’t talk much about package
construction. Initialization is actually quite interesting in Go. It's much--it's sort of
hard to see, but it does a lot for you. It can help you set up things like RPC servers
with almost no code and stuff like that. There’s fall reflection, you can reflect from there,
you can reflect on functions, channels, maps, all kinds of stuff. It’s got interesting
some dynamic typing going on if you wanted to, but you don’t have to use it. There’s
a thing called Embedding that is a little bit like an inheritance, but somewhat more
simple and yet general. There’s iterators that come out of the way. The range thing
works on fours in our channel’s functions, things like that. And there’s some interesting
testing software, but I don’t have time to talk about any of these right here, but
I just want to make it clear there’s a lot more of the language than what I have time
to show you. So let me close this section with another interesting example. This is
a real communications example. Remember, we started this language because we want to build
servers. And one of the problems with building servers in the modern world is there’s this
model of a thread per request, which is quite labor intensive and resource intensive to
run and quite difficult to get right in more languages. And we want to make it easy to
think about having tens of thousands or even hundreds of thousands of threads—-whatever
they are-—working on your behalf. And to prove that we got some way towards that. This
is an example that will create a hundred thousand goroutines and then they can do something.
And what it does, you probably won’t be able to decode this in real time, but what
it does is it has a little function F there that all it does is read a value from a channel,
add one to it and send it out again. So, there left gets one plus, get from right. It’s
that thing inside F. It just passes its token along but adds one to it, okay? And inside
main, we declare the left most piece—-to go your direction—-and then a couple of
variables. And then for the number of goroutines you want to start, we sort of thread a new
piece on and walk away along, but we remember where we started. So, we stitch together a
bunch of goroutines like this, each of which is passing a channel value along to the next
one. And so, we end up constructing, in this case, a hundred thousand goroutines off turning
together like pearls on a string. And each end is waiting for the guy upstream to give
him a value. So, then right at the bottom there after the loop--once we built this thing—-we
say, drop a value into the right hand side and it goes pfft and pops out the left. And
the value that comes out is of course the number of goroutines in the chain because
we’ve added one for each step, okay? So, you can examine that later if it confuses
you, but let me show it to you actually running. Okay. So--oh dear, I think it was the wrong
file—-okay, sorry it took so long. And now, I’ll run it—-now remember this is a little,
a little mac air very fast. That's a hundred thousand threads of control--I won’t say
threads because that’s not how it is done—-but just incase you’re wondering, it takes about
1.5 seconds to manage a hundred thousand goroutines. And it’s real--it’s honest to God management
too. It’s [INDISTINCT], it’s stitch together communication. Doing the communication and
it’s tearing them down. This hasn't created an instant kill, this is a legal honest build,
use them, tear them down. It’s kind of a minimum thing you can do that, but still,
hundred thousand is an interesting number and we could go more but it start to use up
memory. So, let’s just prove that there’s—-anyone knew that. Here we go. So, that’s concurrency
showing that you are going to at least, conceptually, have many, many things. Now, the goroutine
implementation has to worry about real threading and real stuff like that when you’re doing
I/O operations that could block but that is taken care off. So, you are left with a simple
mind example, it’s indicative of something that really works. So, let me talk a little
bit about the status. It’s actually quite a bit to say, we have two complete implementations
in two different compiler technologies. Ken Thompson wrote a suite loosely based on some
of the Plan 9 tools but it’s from scratch, and using the peculiar notation, 6g is the
AMD—-it’s a 64 bit X86 compiler. There’s also a 3D 61 and an ARM which is five for
reasons. Don’t even ask. But anyway, the point is there is a compiler. That’s the
one I’ve been using today. Some are more experimental than the other compiler but as
you’ve seen it, it generates code quickly. The code it generates is pretty good, it’s
not as good as what comes out of GCC, but it’s better than you might think for a compiler
that goes that fast. But, in order to do that, it got it’s own rules and so, the output
is not linkable directly with GCC. But there is a foreign function interface support that
is coming along pretty well. We can call C-code from Go with this compiler just fine and once
we get Swig work and we’re able to call C++ code. And then Ian Taylor, wrote a GCC
front end for Go which is a complete implementation--I should say, by the way, that Ken’s compiler
is written in C for bootstrapping reasons, although, honestly it would be a great language
to write a compiler but it’s written in C for now. And Ian Taylor thing is a C++ front
end for the GCC backend. It generates excellent code with GCC quality but it’s not as fast
it’s about something like four or five times slower. But the real advantage of compiling
GO isn’t the compiler speed, it’s the compilation speed. The whole picture is where
the speed really comes from. And both these compilers supports 32 and 64 bit x86 and with
ARM compiler that Kyle has been working on that’s almost ready—-I think it’s up
to 97% to test suite compliance now. So, we are very close. We have to have it ready in
time for the open source release. And for performance of the generated code, it varies
obviously because it’s different but if you avoid some of the libraries for which
have weak implementations. Typical inter loop kind of performance or standard programming
gets you typically to 10 to 20% range with the GCC tending to be more like—-by which
I mean 10 percent slower than C and Ken’s compiler is typically like 20% slower. So,
1.1x to 1.2x, but this is for a type save, statistically compiled garbage collection
language. It’s pretty nice. And I’m happy to give up 10 percent even with words lost
flowing down, that’s still not very much clock time on the calendar. So, there’s
a Run-time that handles all the memory allocation, garbage collection, stuff like that, the stack
handling stuff which is pretty special but very important. The goroutines support channels,
slices, map, reflection; all of that stuff is built into a real run-time. So, even though
it’s a system language it has a really powerful run-time system including dynamic type reflection.
And it’s pretty solid. It’s improving, it got ways to go especially in memory allocation
and some of the scheduling stuff, but that’s yet to come, but we’re working on it. 6g
has a very good goroutines support and much of them on the threads well and implements
what we call segmented stacks, which is how we keep the footprints small but let them
grow as they need to. GCC goes a little behind on that because Ian has been working on a
few other things lately. But we hope by the end of the year to have all that stuff working
in GCC Go and they’ll basically be at the same stage at that point. But even so, GCC
Go can compile all the code and run it now. The garbage collector, 6g has a simple but
effective mark-and-sweep collector. And this sounds simple, but work is under the way to
do a much better job. We believe, with multi-card machines, you can actually do concurrent garbage
collection with essentially zero latency and very little cost and overhead. And IBM has
this garbage collector technology that we think is pretty exciting. We think building
on that stuff, we can actually make our real goals which are to avoid a lot of the pitfalls
that garbage collector tend to have. And we’ve done work in other languages before that indicate
this really can be done and now that we have multi-card machines we believe that we can
really solve it. GCC Go at the moment has no collector, but, as I said, we're working
on a common run-time, and I hope by the time this collector is done is design to run with
either compiler. It’s part of the general run-time so both compilers will have real
garbage collectors inside of them. There’s lot of libraries, there’s tons more to do,
but we have a pretty good start. We’ve got obviously, OS and I/O stuff. I showed you
some of that. It’s got a nice math, a simple math package. It got strings, good support
for Unicode, rudimentary but functional regular expression implementation. It’s got run-time
reflection, command-line flags and logging, which are very nice to use. It's got full
hashes and crypto and all that kind of stuff. It's got a really good testing tool and a
library to support it, standard networking libraries just like you’d expect, including
a native RPC implementations. It’s kind of pretty. There’s a really interesting
template library based on some work that Andy Chu did that let’s you write HTML or, in
fact, anything at all using this to generate really simple data driven page generation.
It's really quite nice. Andy gets most of the credit for that. There’s a lot more,
but you can see there’s actually quite a bit in place already. So, one of the most
interesting programs written in Go is a pair of things that are related--they share a lot
of code--called Godoc and Gofmt. Godoc is analogous to Javadoc. It serves documents
to request to look up, you know, what this package does or what that function does. And
there’s a set of links listed there. Golang.org is a top-level guide that’s running Godoc.
It serves the landing page. And underneath that, you can find all the other documents
specifications, editorials, and FAQs, and stuff like that. But if you dig down into
the package subdirectory, that’s really interesting, automatically generate the package
documentation is especially quite rich. And then under the source directory, the source
gets served, but, of course, you can get out of this code repository, too. The difference
is that the source is processed by the coding Gofmt. The Gofmt is a pretty printer and all
of the coding repository has been formatted by Gofmt. So, rather than set a bunch of style
rules, we have a program that says this is what a code looks like, and you just run through
Gofmt when you check it in and that’s, just settles all those arguments. If you want debate,
if you wanted debate, we got to debate by changing Gofmt. You can’t debate by changing
a document, and I think it’s actually, it does an amazingly good job. Actually, Robert
[INDISTINCT] a good job. We have a debugger. It’s not quite ready, but it’s pretty
close. I hope by the end of the year we'll something functional but we’ll be happy
to show. But it's coming along and it will work with either environment but at the moment
its working in the 6G world primarily. Gccgo users can of course use gdb. Gdb doesn’t
understand the symbols tables. They're coming out of Ken's compiler, so it doesn’t work
very well with that. But with Gccgo compilation, you can use gdb, but it thinks that the C
program is debugging and there’s some weirdness in the symbol table. And also it doesn’t
know anything about the run time, which is a critical thing when you’re debugging on
an environment like this. So, we really got to get our debug up to scratch. We had a summary
in turn. Austin Clement was here working on that. It's pretty close, but not quite ready
for real use. One question everybody wants to know is what about generics. And the answer
is Go doesn’t have them yet. We don’t understand exactly what they do in Go’s
world. They’re quite subtle. The easy examples are easy to write down. It's obvious what
the easy examples do, but the complete, correct definition is going to be quite complicated.
We want to make sure we get it right. In some ways, Go makes it simpler because there’s
no type inheritance, and that eliminates one branch of complexity in generics. But on the
other hand, you can put methods on things that are values of arbitrary size, so, that’s
a consequence, and the other directions are complicates and simplifies at the same time.
And we just don’t think we understand it well enough to do them yet. Also, in the current
world, although that would be definitely useful and could solve a lot of problems, the map
and slice implementations and the interfaces themselves actually cover a lot of the sort
of obvious examples for generics, which is not to say they wouldn’t cover a lot of
others if they came along, but the need isn’t quite as acute as it is in the language. It
doesn’t have those features. You can in fact build collections fairly nicely using
what’s called the MT interface, which is just interface open close. That’s an interface
that implements no methods because everything in the world satisfies the MT interface. It's
kind of a little bit like it but in a completely different meaning the object in Java. And
you can build collections that use. There's quite a few checked in, but they have the
disadvantage that they’re not type safe since you have to unbox manually and stuff
like that. They’re not really what we would propose to do instead. It's just what we’re
using for now, why we struggle at this question. So generics, not yet but they're very subtle.
It’s interesting in the codes workbook, Josh Black has a long discussion about them.
And I think most people think that Java generics works really well including Josh, but he points
out they're actually quite a bit harder to get right than you think, and then maybe it's
time to think really hard before you put them in. So, they may come but they're not there
now. And, of course, there’s a million of other thing. Where’s my feature? Everybody
who programs has a feature they want, and chances are that some of the things you really
think are important are missing, or they might be there but not in the way you’re used
to. A really good example is inum but there is no iota. And iota's an interesting thing,
but it's not an inum. It's different. So, it may not be there, but there may be some
way to do what you want. It’s just Go is different or almost as good or maybe even
better. But why is it a feature there? Well, maybe it doesn’t really work in the language,
you know. Like there’s no point of arithmetic, point of arithmetic is nice but we can’t
do a point of arithmetic and make a language safe, there just not there. And the compiler
makes up for trying to compile a way some of the inefficiencies you get by having your
index and everywhere but on the other hand you got a safe length. So, a lot of the things
the people expect the language like this were not there because they break the rules and
we don’t have them. Or at least they break principles about what we think for language
should do. And there’s also a possible--like generics is a good example. They're just not
on top of our list. It doesn’t mean it won’t happen. Union types is another one we’ve
been thinking about. Actually, I think it would be a very good proposal for them, but
we haven’t done that yet. So it’s possible some of the things you’re finding for will
actually occur fairly sooner or not too far out. But it’s a different off language that
even if it doesn’t have the features you want, it may have features you haven’t used
before, if I can guarantee that some of you haven’t used before, the interface stuff
is very interesting. And don’t let the lack of things you expect stop you from playing
with things that are there and seeing that it does actually do of some pretty interesting
stuff. And a lot more information on this topic available is actually explicit language-assigned
FAQ on the website and it talks about a lot of the "why things aren’t there" things.
So, to conclude, I think we really have a nice language. I’m having more fun programming
than I’ve had in a long time because I feel like I’m getting work done, because I’m
getting work done. It’s early yet. I think the language is going to evolve some more,
these things we know, but a lot of the basics are locked down pretty well. I feel pretty
comfortable with them. It’s a very comfortable language to work in. It’s very productive.
You can write code really fast and have it work and be safe. There’s tons of documentation.
There’s a specification, complete spec of the language. There’s simple to trial for
beginners. There’s a document called Effective Go, which is growing to sort of explain idioms
and how you think about things and language differently. There’s some FAQ, and there's
even other things than that. All the implementations are available as open-source, the 6GHG5G suite
and all its tools, the gzgo and all that stuff is also in the different place, but it’s
also going out and it will be linked from the landing page. And so, if you want to try
it, go get it. If you want to help, please do it. There’s tons of work to do to build
it up to another level. We really are welcoming people to come in and talk about stuff, especially
if they want to help us do some interesting library work or build new tools, there’s
plenty of room for things to happen. So that’s our site and that’s our language. Thanks
for listening.