top | item 5600883

What Python developers need to know before migrating to Go

104 points| rachbelaid | 13 years ago |blog.repustate.com

103 comments

order
[+] wting|13 years ago|reply
> The code you write with Go just seems to be correct. I can’t really put my finger on it, but somehow once the code compiled (and it compiles QUICKLY), you just get the feeling that it’ll work (not just run without error, but even logically be correct). I know, that sounds very wishy-washy, but it’s true.

This statement needs to be qualified.

Switching from an interpreted to a static language will catch a certain class of bugs upfront. I've rewritten some small programs from C to Go, and the same logic bugs are present in both.

In this sense, switching to Go is no different than switching to Java/C in terms of the bugs it will catch. There's nothing in Go that sets it apart from other static languages in this respect (unlike Haskell).

> It’s very similar to Python in terms of verbosity (or lack thereof) and it treats functions as first-class objects, so functional programming is easy to reason about.

Where is map, reduce/fold, filter, scan? Go doesn't support functional programming primitives due to lack of generics.

I may not have written enough Go programs, but I find Go marginally less verbose than C thus far (ignoring concurrency). Channels and goroutines and are its most interesting features.

[+] viraptor|13 years ago|reply
> you just get the feeling that it’ll work (not just run without error, but even logically be correct)

This is the feeling I get from good strongly/statically typed languages too. My best example is a ray tracer written from scratch in haskell. It took a good couple of hours, but then once it actually compiled it run the first time without error (but rendered everything behind the camera) and exactly as it was supposed to work on the second try.

I really like languages which give me that kind of feeling.

[+] georgemcbay|13 years ago|reply
There are, in fact, many small features of Go that make it more safe than C in terms of runtime correctness. eg. it has much stricter rules about automatic type conversion (you can't assign one int/char type to another differently sized int/char type without an explicit cast), it has sane built-in string handling much less likely to result in buffer overflow style issues, you have to go way out of your way with the unsafe package to blow your foot off by doing pointer arithmetic, etc, etc. None of these small things by itself adds a lot over C or C++, but combined they really add up.

I did C/C++ programming professionally for more than 10 years (and come from a static language background) and I share the OP's view that compilable Go code is much more likely to be correct than code in other languages I've used, even static ones... the fact that the Go code compiled is of course no guarantee it'll be correct, but the Go compiler enforcing the rules of the Go spec does eliminate whole classes of common gotchas even ones that bite you in C/C++ and other compiled languages.

[+] pjmlp|13 years ago|reply
For me it is mainly a C successor that catches up with what the Pascal family of languages has been offering since the mid-80's, in terms of compilation speed, modules, concurrency and safety.
[+] hsitz|13 years ago|reply
"The code you write with Go just seems to be correct."

Ironically, Eric Raymond made very similar statements _about Python_ in his 2000 article explaining why he had moved to Python from static languages and from his previous dynamic language of Perl:

"When you're writing working code nearly as fast as you can type and your misstep rate is near zero, it generally means you've achieved mastery of the language. But that didn't make sense, because it was still day one and I was regularly pausing to look up new language and library features!"

"This was my first clue that, in Python, I was actually dealing with an exceptionally good design. Most languages have so much friction and awkwardness built into their design that you learn most of their feature set long before your misstep rate drops anywhere near zero. Python was the first general-purpose language I'd ever used that reversed this process."

____and again, regarding a little program whose code he links in the article____. . .:

"That doesn't look too bad for deep black magic, does it? Thirty-two lines, counting comments. Just from knowing what I've said about the class structure, the calling code is even readable. But the size of this code isn't the real shocker. Brace yourself: this code only took me about ninety minutes to write—and it worked correctly the first time I ran it."

"To say I was astonished would have been positively wallowing in understatement. It's remarkable enough when implementations of simple techniques work exactly as expected the first time; but my first metaclass hack in a new language, six days from a cold standing start? Even if we stipulate that I am a fairly talented hacker, this is an amazing testament to Python's clarity and elegance of design."

"There was simply no way I could have pulled off a coup like this in Perl, even with my vastly greater experience level in that language. It was at this point I realized I was probably leaving Perl behind."

http://www.linuxjournal.com/article/3882

[+] ihsw|13 years ago|reply
Personally I find its dependency resolution to be one of the highlights of Go, and furthermore since circular dependencies are disallowed then that eases maintaining much larger and more complex codebases.
[+] fixxer|13 years ago|reply
> This statement needs to be qualified.

Yeah, "seems to be correct" is a little wishy washy... I'd argue that Go has enough syntactic sugar to be easy to learn from a Python background, but enough structure that it encourages good software engineering practices.

[+] pbreit|13 years ago|reply
> This statement needs to be qualified.

The whole paragraph is a qualification. How much more do you want??

[+] jdiez17|13 years ago|reply
You can actually do functional programming in Go. Lack of generics just means you have to think harder.

In fact, a friend of mine did a Go library to write functional-style code: https://github.com/tcard/functional

[+] jgrahamc|13 years ago|reply
A very large amount of this is "Moving to a statically typed language".

1. "Different assignment operator is used depending on whether you are inside & outside of function ie. = vs :="

= is an assignment, := is a declaration and assignment at the same time. It's true that you can't := outside a function (which I think is silly), but the comparison should be between these two:

    var foo string = "Hello"
    foo := "Hello"
2. "Else (or else if) has to be formatted properly, where the else is on the same line as the curly bracket from the if clause. Weird."

Whereas, coming from Python where indentation matters. Weird :-) Both are style conventions enforced by the language.

[+] mratzloff|13 years ago|reply
The same-line convention comes from automatic semicolon insertion at the end of lines. A semicolon is inserted if the line ends with "}", but not "{"... hence, "} else {". This is also the reason multi-line lists require a trailing comma.
[+] shadowmint|13 years ago|reply
Come on, those are the two weirdest things about go syntax, especially for new comers.

(Honestly, why can you not 'for var x = 0; ...'? and only 'for var X := 0; ...; ...' but immediately below var x = 0; is just as valid. The := / var syntax in go is just plain weird).

Go is also the only place I've ever seen this syntax:

   if blah {
     ..
   } else {
     ..
   }
Maybe that's popular in some obscure places, but it is weird they made that the only valid syntax.

I mean, fair enough, Go has its own syntax, but these are pretty valid gripes.

[+] mratzloff|13 years ago|reply
Many of these points are only really relevant to a Python developer new to statically-typed languages. For those points you could substitute s/Go/Java/g and it would be just as true, except that someone new to Java would probably lean on generics more than they should.

As for the other points, it would be nice to have more built-in types like a Set type, to be able to ignore "unused dependency" errors when running "go install", etc.

Oh, and I think he missed the most surprising thing about Go for newcomers: that "if" creates scope!

[+] ominous_prime|13 years ago|reply
> Oh, and I think he missed the most surprising thing about Go for newcomers: that "if" creates scope!

Go is block scoped, and if statements are blocks. I don't see this as surprising.

I agree some set operations would be nice, maybe using an interface like Sort, but you can use a map as a basic generic set data structure. This is how many language implement a set anyway.

[+] sanxiyn|13 years ago|reply
The real problem is that a set type needs to be built-in, i.e. you can't build satisfactory one yourself, because you don't have generics.
[+] Dylan16807|13 years ago|reply
How many sane languages have function scope rules? Python has them, that's one. Javascript is a mess but might count. PHP is not sane at all. Most other things have block scope as far as I know.
[+] ominous_prime|13 years ago|reply
This seems more like a list of things developers need to know if they've only ever used python.

Go has different syntax and rules than python, but so does C, Java, Erlang, and so on. I don't get why this is such a surprise. Don't approach a new language assuming you can directly translate from your last language du jour, and you'll be much happier.

[+] grey-area|13 years ago|reply
No constructors, so common idiom is to create NewType() functions that return the struct you want

It would be nice to see official constructors in Go, to encourage consistency, it feels a little ad hoc at the moment.

You can’t have mixed type data structures. Maybe it’s not kosher, but sometimes in Python I’ll have a dictionary where the values are a mix of strings and lists. Not in Go, you have to either clean up your data structures or define custom structs

I didn't understand this point. If you want you can use a map[string]interface{} to store arbitrary mixed types in a map (dictionary), though obviously no type checking is then done on the dictionary, but you could define an interface Inter which both types conform to and use map[string]Inter instead so that you know what you're getting and that it will respond as you expect.

If I want a list of just the keys or just the value, as in dict.keys() or dict.values(),

It'd be nice to see some enhancements to map for common operations like this, it's something I missed from Ruby. It'd be nice to have an ordered map in the standard library as well.

Else (or else if) has to be formatted properly, where the else is on the same line as the curly bracket from the if clause. Weird.

This sort of grammar quibble mystifies me - one of the nicest things about go is gofmt and the recommended formatting - I like that, for trivial points of grammar like this, there's only one way to do things which is considered correct. This isn't the style I'd personally use elsewhere (in C for example), but it's great that all Go code is formatted in exactly the same way - it makes it easier to read, and really is not hard to pick up.

If you’re using JSON and your JSON is a mix of types, goooooood luck. You’ll have to create a custom struct that matches the format of your JSON blob

This does have the advantage that you know what you're getting, and can't unmarshal unexpected objects by mistake when fed malicious/broken JSON.

[+] bayesianhorse|13 years ago|reply
Switching from Python to GO is a big boost in speed and a big sacrifice in terms of third party code.
[+] pekk|13 years ago|reply
Why is it necessary to 'switch' at all? Can you only hold one language in your head at once?
[+] JulianMorrison|13 years ago|reply
map[rhubarb]bool is how Go does sets and []interface{} is how Go does heterogenous lists.

Also you can unmarshal JSON into an interface{} variable and get a mix of map[string]interface{} and []interface{} that you can deconstruct via type assertion if you know what to expect, so you can be a bit python-ish about JSON if you don't want to read it into structs.

[+] stevvooe|13 years ago|reply
> map[rhubarb]bool is how Go does sets

Actually, you should use map[rhubarb]struct{} since a struct{} requires no storage. You can test membership with this:

    _, ok := m[strawberryRhubarb]
[+] unknown|13 years ago|reply

[deleted]

[+] tikhonj|13 years ago|reply
Haskell has tuples. It also has pattern matching, which is destructuring done right. So I'm not sure exactly what you're getting at.
[+] orangethirty|13 years ago|reply
I just jumped into Go a couple of days ago. Was minding my own business when I suddenly arrived at its homepage. The online tutorial seemed interesting and I began completing it. Well, hello, where have you been all of my life? Go is quite something. To me, is like the right mix of C and Python. It reads very well, and is very minimal. I have been spending all of my night learning it. Have had so much much, in fact, more fun than I ever remember. Right now, I'm not very productive with it, but give me a few days. I never paid much attention to it, because what could be better than Lisp or Python? Go is not better, but its in the same category as those two (for me, at least).
[+] nphase|13 years ago|reply
> If you’re using JSON and your JSON is a mix of types, goooooood luck. You’ll have to create a custom struct that matches the format of your JSON blob, and then Unmarshall the raw json into an instance of your custom struct. Much more work than just obj = json.loads(json_blob) like we’re used to in Python land.

I believe you can use json.NewEncoder().Encode() to arbitrarily deal with interface{}'s

[+] oddshocks|13 years ago|reply
If only the site would load.
[+] mattsfrey|13 years ago|reply
This. I've been trying it off and on for half an hour now, how did all these other people manage to see it?
[+] reyan|13 years ago|reply
Did you use Python bindings for libsvm?
[+] sebjapon|13 years ago|reply
the link doesn't work for me. anyone knows why?
[+] michaelochurch|13 years ago|reply
One thing I can't wait to see (maybe when the Go ecosystem is more mature) is Gojure, a Clojure that runs on top of the Go environment. That would be badass.

ETA: I realize that it just looks like I'm spouting opinions if I don't get into why it would be badass. Essentially, Go is a language designed for production systems in one of the most demanding large-scale software environments on earth. Compilation is rapid, and the language does a lot of things that force code quality. The problem is that it still feels a bit verbose. Putting a Lisp on top of that (and Clojure is my favorite Lisp) would be really interesting.

[+] kyllo|13 years ago|reply
Out of curiosity, are there any particular reasons why you like Clojure more than other Lisps/Schemes? I've played with it a little and found it kind of weird due to no car/cdr/cons, no TCO, loop/recur/trampoline, the usage of [], and various other quirks. It's a Lisp but you can't just write Lisp code in it, it requires learning new idioms. But I'm not good enough at Clojure yet to know what advantages it has over other Lisp family languages, aside from the Java libraries. What features of Clojure do you particularly like?