Instantly, and progressively, by starting at the top and working through a single document that is both a reference and a guide.
Beautiful work.
Edit: One change I would make is to change p := pair{3, 4} into p := pair{x: 3, y: 4} which helps your declarations keep working in the future when you extend or modify the definition of `pair`.
Go isn't a Lisp, last I checked. I am referring to "Pair" as a class/interface in an OO language. If you're using Pair to construct a linked list in a OO language, I salute you, but that's even more of an anti-pattern.
Pair is an OO anti-pattern because it's an arbitrary grouping of two things in a generic container, and you shouldn't do that in OO - classes are cheap. You should make a class that represents what the collection of those two things actually are. Typical field names in generic Pair objects are 'left' and 'right' or 'first' and 'second' which tells you nothing about the values you stick into them (except the types, if you're using a strongly typed language). If, as suggested in the example, the pair holds a 'x' and a 'y', a better choice could be to call it "Point" or even "Point2D". If it's a key/value pair from a map data structure it should be "Entry" with fields "key" and "value" - etc.
It is worth pointing out that the pair in question is indeed an {x, y int} (using Go's ability to elide repeated types, so this means both x and y are an int). The name may be poor, but since it also will in general use be paired with the module name, it may not be, either. "Pair" is a poor name, rationals.Pair might not be.
A truly generic Pair in go would be Pair{interface {}, interface{}}, and that would be a code smell. (Only a smell though, since it's possibly part of some larger construct that is basically getting around Go's compile-time type system and replacing it with a run-time check.)
It's generic, not in the Java-generics sense of the work, but in the sense that x and y are generic names - they don't tell you what x and y are. Yes, they are of type int, but are they apples or oranges? In the example, they are indeed just two numbers that we chose to keep together, although the name and field names suggest that the author has a point in mind.
rationals.Pair is still a poor name, it's a pair of what and for what purpose? Assuming you're referring to rational numbers, ratio struct {p, q int} is better.
In my C code I've been moving away from distinguishing primitive types by name alone, preferring to wrap them in single-element structs to get some type safety:
Yes, it's less informative, because you're missing the context of why the apples and oranges are lumped together in the pair. FWIW fruit_basket_t is poorly named too, since fruit baskets not things that can count apples and oranges (and nothing else), they are generic containers capable of holding all kinds of fruit.
I like the single-element structs. I've been finding myself doing that more and more in Java and I quite enjoy it. First epiphany was replacing bool with enums.
I don't think "fruit_basket" (or "fruit_counts", say, addressing your later point) really gives much more clue as to why you're grouping these things than does the templated pair. When there is an informative name, use it, to be sure. Occasionally there's not much more reason than "I am using both of these elsewhere. This is much more the case when things are used locally than when they are exposed in interfaces, to be sure.
Agreed. Diving in to examples is the best way to learn. I'm usually wary of these "Learn X in Y minutes" posts, but this one is great - maybe due to Go's succinctness?
MULTIPLE return values?! My mind is BLOWN. That's awesome. My work is all in Java and there are so many times on my last project where that would have been helpful (I know I can do it by creating a map or an array or something, but that's stupid and extra code that I shouldn't need to write).
I really hope to be able to write Go professionally at some point, it is a really nice language to write in.
Well, all I've written since college has been Java, so this is all new to me. I've only briefly checked out Ruby and Python, and not enough to really know that much about either language.
This is the first one-liner I've read that actually explains something useful I can do with higher-order type inference. Preventing errors at compile time doesn't count; doing something is run-time by definition.
As an easy to follow (though questionably idiomatic) example, consider the typeclass Default:
class Default a where
def :: a
and an unwise pair of instances:
instance Default Int where
def = 7
instance Default String where
def = "foo"
This means I can say:
3 + def + length ("c" ++ def)
and get back 14. Note that which "def" depends on the type expected where it is used.
---
It's not limited to values, either. Consider the "return" function in the Monad typeclass:
return :: Monad m => a -> m a
which is a function that takes something and returns that something wrapped in a monad. Which monad? Whatever is expected at the call site.
[1, 2, 3] ++ return 4
gives us [1, 2, 3, 4] because list is a monad and return for lists gives a single element list, whereas
putStrLn "foo" >> return 4
gives us an IO action that, when executed, prints "foo" and yeilds a 4.
---
A super complex example is variadic functions like printf, with the type
printf :: PrintfType r => String -> r
PrintfType can be a String or IO (), giving you something like C's sprintf or printf based on the call site (which is itself cool), but it can also be a function that takes an instance of PrintfArg and gives back some new PrintfType (in an interesting intersection with currying).
Meh, not really. In ruby `return x, y` is just syntactic sugar for `return [x, y]`, ie returning an array. It's also an indication that you probably need a class.
Wow, I'm not really interested in learning Go, but I was drawn in and made it all the way to learnInterfaces. Congrats!
One question: why have named return values (in learnMemory) if you return something different? If you didn't have a return statement at all, would the function return the final value of p and q?
> One question: why have named return values (in learnMemory) if you return something different? If you didn't have a return statement at all, would the function return the final value of p and q?
This looks very similar to the "easter egg" that the F# team put into visual studio.
When you create a new F# project you can select F# Tutorial and it generates a working project with a source code file that is an introduction to the language and its features.
I'm tired of reading that this or that language/framework is "easy-to-understand" and "fun" to use. That's a subjective statement and mostly not true. Writing code is a means to an end, you want the output of a program not a bunch of lines, so I don't see how it could be fun (which is repeated over and over again in the official documentation and various slides and talks). And the concept of easy-to-understand is determined by the level of experience of an individual plus a whole lot of factors that are beyond us, not least of which is the sheer brain power.
What we mean: All of us on the team have a lot of fun writing Go. We often show each other little pieces of code that delight us. This seems to happen more when we work in Go than in the other languages we use (or have used), and so we attribute the fun-ness to Go. Pretty straightforward. I'm sorry you're so tired of it.
Wow, I didn't expect to get a response from an actual Googler, working on Go no less. Anyhow, I also remember when people were saying that Java was a fun language to work with, but I still have to find a single engineer who doesn't think of it as slightly more than a pain in the ass. It's all a matter of right-sizing expectations; using and objective language keeps you from being called out should those expectations fail to be matched.
That said, I've already professed my love for the Go language, which I consider the spiritual successor of the C programming language.
Java was fun to play with back in the early days. It was fast, had a VM, garbage collection and was OO. Sadly the fun was gradually removed over the years as a result of design-by-committee and a desire to try to solve some of its core issues.
Fortunately you can still have fun on the JVM, even though I prefer to avoid it these days given its current custodians.
I've come across many people that program as a means to an end. They don't enjoy it, it is just what they need to do to get the machine do what is fun, which is folding proteins, modeling ocean currents, driving the CNC, or what have you. For me, the actual application is fairly incidental to the programming and design part, which is where the fun is for me.
If I could unilaterally make just one change to Go, I'd adopt C#-style nullable types, and change everything to be nonnullable without the extra sigil (or whatever, I have no passion about the syntax itself, just the feature). This would produce, say, map[string]string vs. map?[string]string. The first would not be permitted to be null, the second would.
It would be my choice because unlike a lot of other pet ideas which would radically change Go into a new language, I'm pretty sure this would have hardly any effect... excepting of course to remove the Billion Dollar Mistake from the next up-and-coming language.
Well, I'm more or less a programming language nerd and these kind of things just hurt =).
Just try to pass a 'map' or a 'struct' to an other function. The 'map'
behaves like passed by reference and the 'struct' behaves like passed by
value. If you want to pass a 'struct' by reference than you have to use a
pointer to a 'struct'.
Seriously? What kind of ad hoc programming language design is this?
The zero value for a map is nil. The zero value for a struct is a valid struct whose fields are all zeroed. So for pair, that would be (0, 0). The zero value for a pointer is nil. If you had said `var p *pair`, then it would be a pointer to pair, and it would be nil, and you would get a nil panic error.
Just out of curiosity, I ran format in play.golang.org, and it creates tabs with 8 spaces -- really? Is that what the command "go format" will do, too? Is standard go formatting tabs with 8 spaces?
`make` also takes an optional size param that will let you pre-allocate a certain amount of memory if you know the size the map will grow to in advance.
Where exactly does the struct pair implement the Stringer interface? Is it when the String method was added to it? What if you have interfaces with similar names?
The problem of interfaces with similar names is actually no different than the problems of, for example, packages or functions having similar names. It's down to you to avoid naming things in a confusing manner.
There is no "implements" in go. A type either provides the methods to satisfy an interface, or it doesn't. The name of the interface doesn't matter, and it can satisfy an many interfaces as it wants.
Thanks! Inspired by you, just wrote the Romanian translation for Python. Maybe I'll do Go next :)
Seriously thinking about writing the Django equivalent of Michael Hartl's tutorial for Rails. Intimidating as it's a lot of work, over 100k words. Any people would like this? I really could not find a Django/Python equivalent.
Uh, I think it is. I can't go three articles without seeing Go mentioned.
I'm going to get downmodded to gray, but either this tutorial is missing something or Go is way over-hyped. I saw nothing special in the language at all, I have no idea what all the obsession is about lately.
I thought the comment "x == 1 here" could use a little more explanation (I figured it out, though, so maybe not.) I also found the function signatures confusing, especially the function with a local variable q that is nothing to do with its returned value q -- seems like a bit of a wart in Go. (Being able to assign return values vs. using return, as in Pascal, seems like an obvious reason to declare return values this way. Perhaps this feature exists but is not explained.)
I've been reading Chisnall's Phrasebook and Summerfield's Programming in Go books. Both are well done as far as descriptions of language features and standard lib go (covering 1.0), but are a little short on extended code examples.
Does it bother anyone else that Go supports the GOTO statement? I would've thought GOTO an obvious construct to leave out when creating a new language, to protect programmers from themselves? (See Dijkstra on 'GOTO statement considered harmful')
Yes, but you shouldn't ever see single-line ifs in go, because gofmt forces all of them to be multi-line.
This is one of the strong points of go (whether you like it or hate it): gofmt imposes the same formatting rules for everyone using the language. It's not a choice for you (or your project) to make. Period.
Learning to use some newfangled editor and figuring out how to install plugins for it when the editor you've always used works just fine sounds like much more work than running gofmt. :)
Instantly, and progressively, by starting at the top and working through a single document that is both a reference and a guide.
Beautiful work.
Edit: One change I would make is to change p := pair{3, 4} into p := pair{x: 3, y: 4} which helps your declarations keep working in the future when you extend or modify the definition of `pair`.