

What Python developers need to know before migrating to Go - Nogwater
http://blog.repustate.com/migrating-code-from-python-to-golang-what-you-need-to-know/2013/04/23/

======
n1ghtm4n
Some thoughts after spending ~100 hours with Go.

\- Function overloading is a major convenience that you will miss. There are
differently named versions of every function and you will call the wrong
version with the wrong arguments _all the time_. The number of functions in
the standard library could be reduced by at least 1/4 if they'd got this
right. The official FAQ
([http://golang.org/doc/faq#overloading](http://golang.org/doc/faq#overloading))
explains that leaving out overloading is "simpler", meaning _simpler for
them_.

\- Default parameters are a major convenience that you will miss. Using
strings.Replace() to remove some chars from a string? Don't forget to pass the
-1 at the end, asshole! The -1 says don't put a limit on the number of
replacements. In Python there would be a max=None default parameter and this
would never bite anyone.

\- No named arguments, because fuck readability.

\- Forcing me to handle errors is great. Having 20 different ways to do it is
not great. Examples: fmt.Errorf(), fmt.Fprintf(os.Stderr), errors.New(),
log.Fatal(), log.Fatalf(), log.Fatalln(), panic/recover...

\- Using && and || for logical operators in this day and age is just
ridiculous. Why do people keep inventing programming languages as if Python
doesn't exist?

\- Don't think that just because the Unicode guys invented Go that Unicode is
going to be easy. Their solution is not to create an airtight abstraction
layer between chars (or "runes" WTF?) and integers. Their solution is to
provide almost no abstraction and force you to deal with the inherent integer-
ness of all characters. Example:

In Python:

    
    
        len("нєℓℓσ")  # 5, because there are 5 chars

In Go:

    
    
        len("нєℓℓσ") // 12, because there are 12 bytes
        utf8.RuneCountInString("нєℓℓσ") // 5, plz kill me i am an abomination
    

tl;dr If you're inventing a programming language for human beings (not UNIX
gods), try it out on a group of smart high school students first. It will be a
humbling experience.

~~~
dbaupp
> Using && and || for logical operators in this day and age is just ridiculous

No it's not, it takes 10 minutes to learn that && means and and || means or
(maybe a little longer to get the hang of it properly), and this knowledge
transfers to many programming languages.

(This is a little like arguing "we shouldn't use + when English has a
perfectly good word 'add'"; symbol reasoning is valuable.)

~~~
count
'+' is damn near universal. '&&' && '||' !universal.

~~~
dbaupp
They're not universal, but they're essentially so; pretty much everyone who's
used C(++), Java, C#, ... has seen && and ||, and knows what it is. And people
who've only used languages with 'and' and 'or' will only take a few minutes to
get up to speed (they have the option of spending longer complaining about it
if they want).

~~~
ak217
> people who've only used languages with 'and' and 'or' will only take a few
> minutes to get up to speed

No. Cognitive overhead. You pay for it every time you parse these words in
your brain. You pay for it by reducing the number of nested/combined clauses
that you can parse on the fly.

(This is far from the only readability issue with Go, by the way, and you're
right in that it's among the more superficial ones. The language is designed
so well in all ways except the one that matters the most, it hurts.)

~~~
beagle3
No, laziness.

&& is pronounced "and" but actually means "shortcircuit left-to-right-
evaluated and".

If you're coming from a Pascal (or non-programming) background, you do not
assume either left-to-right evaluation order, nor short circuit evaluation.

The cognitive overhead is always there, because whether you like to admit it
or not, programming is applied math, and exact meaning is very important;

e.g.:

    
    
        if a == 0.0 or b/a > 3 then launch_missile();
    

Without the "cognitive overhead of knowning guaranteed left-to-right + short
circuit", this code is wrong.

The hypothetical "newbie programmer who can write a working program but has
cognitive overhead deciphering &&" is a mythical creature that does not
actually exist.

------
beering
Some of the things they listed are dubious...

 __Writing to a file, there’s File.Write([]byte) and File.WriteString(string)
– a bit of a departure for Python developers who are used to the Python zen of
having one way to do something __

Simply because it 's not currently feasible to write a function that can have
multiple type signatures (via overloading, generics, etc.).

 __Going between []byte and string. regexp uses []byte (they’re mutable). It
makes sense, but it’s annoying all the same having to cast & re-cast some
variables. __

There are actually two different versions of each regexp function: one for
strings, one for []byte. Maybe they 're using a different version?

 __No tuples, have to write your own structs or use slices (arrays) __

Actually, you can declare a fixed-length array as a type. So if you need to
return a triple of ints, you can declare the return type to be [3]int and have
the type system check that you 're actually returning an array of ints of
length 3.

Similarly, a lot of the other bullet points are natural results of having a
static type system.

I was expecting more points like:

* you can't monkey-patch functions into external libraries like you can with Python modules * no generics, so you can't write a generic "map" function, for example * no preemptive multitasking, so one goroutine can wedge the entire program * passing around arrays and structs is by value, leading to unexpected allocation and memory usage * pointers

~~~
pcwalton
> Actually, you can declare a fixed-length array as a type. So if you need to
> return a triple of ints, you can declare the return type to be [3]int and
> have the type system check that you're actually returning an array of ints
> of length 3.

That's different from a tuple as it is commonly known in Python and statically
typed languages. Tuples can be heterogeneous in languages like Python, OCaml,
and Haskell, which Go fixed length arrays can't be. For example, in Go you
can't have `(int, float)`.

~~~
khyryk
Something like this?

[http://play.golang.org/p/6nvdLWOi5D](http://play.golang.org/p/6nvdLWOi5D)

~~~
tikhonj
Not quite. What you have is a _single_ type interface{} that happens to be the
super type of all other types. You still haven't solved the issue of having
multiple different types in a tuple--you've just thrown all the type
information away!

Think of a tuple as an anonymous struct. (Or perhaps think of a struct as a
tuple with labels :P.) We want to statically differentiate between a pair of
ints, a pair of strings and an int, string pair, which we simply can't do with
interface{}.

~~~
Ziomislaw
RTFM! of course you can, just switch on a type

    
    
        switch x.(type) {
        // cases
        }

~~~
pcwalton
The parent post said "statically".

------
alok-g
>> No built-in type for sets (have to use maps and test for existence)

Is there any particular reason for this? Sets are so fundamental to
mathematics and beyond that I am concerned right away about this. Sure you
could use a map as a replacement, but what happens to "user experience"?

I do not get this for other languages as well. Data structures that are
present in nearly all computer science books are often not built into the
language or standard libraries, like trees, graphs. Reasoning given is that
some other data structure could serve as a replacement (never mind that the
programmer's intentions are not directly reflected in the code anymore), or
because it is considered too removed from practical usage, or because some
third-party library includes it. I do not buy any of these arguments.

~~~
Zergy
Every possible way to represent a set is a very thin wrapper around an
existing data structure that is commonly implemented. There isn't a generally
applicable way to represent a set. All sets are simply existing structures
(BitVectors, Linked Lists, BST, or HashTables) with functions like Union and
Intersection being tacked on and all have very different performance
considerations.

Basically there really isn't a general purpose way to make a set and it’s not
a fundamental component of programming, it is a modified HashTables or what
ever. So I argue sets don’t actually exist in CS because you can’t represent
one as it exists mathematically. You are simply tacking union and intersect to
an existing data structure.

~~~
alok-g
This would make sense for the case of a set. But does then Go provide (or
intend to provide) these other data structures ("BitVectors, Linked Lists,
BST, or HashTables")? Does it provide a sorted linked list?

~~~
cmccabe
A bitvector: []bool

Most of the time, you would use map[key]value rather than your own hash table
or BST.

If you need an implicit linked list, there is one in the standard library:
[http://golang.org/pkg/container/list/](http://golang.org/pkg/container/list/)

~~~
alok-g
Yes, I noted that list container. If I need a sorted list, do I need to do
that myself (which is OK though not ideal)? Or again there is some other
container that can work possibly with a wrapper around it to emulate a sorted
linked list?

~~~
cmccabe
I think the thing to do is just to write a function to keep stepping through
the list until you find the right place to insert, and then just use
container/list.

Sorry to be "that guy" who questions the question, but sorted lists aren't
really a great data structure. As you probably already know, insertion is
O(N), where N is the total number of elements in the list. It might be better
just to use the GoLRB library, which provides some always-sorted tree
structures.

~~~
alok-g
You are right. I had a very specific case where I needed a sorted list. I do
not recall why anymore.

------
phren0logy
I can't help but feel like criticisms along the lines of "you have to be more
precise with what you want, because unlike python it won't let you get away
with blah" and praise like "it seems to run correctly as soon as it compiles"
are two sides of the same coin.

~~~
TylerE
They are, for sure. The difference, I'd say, is that compared to most other
mostly-static compiled languages, Go generally feels a bit more velvet glove
about it, rather than iron fist. The language principle of warnings are errors
really helps here, as you tend to figure out potential issues sooner rather
than later, and via a clear error message rather than subtle misbehavior.

~~~
Arnor
Also, if you're using Google App Engine SDK it can compile in realtime (i.e.
every time you save a file in the project). So if you have one terminal open
to the dev server process and another for your editor, you get instant
feedback each time you save. It's a very Pavlovian experience :)

~~~
morpher
If you use vim, the syntastic[1] plugin has go support and gives you this sort
of feedback directly in the editor (for any go code, not just app-engine --
and many other languages) every time you save.

[1]
[https://github.com/scrooloose/syntastic](https://github.com/scrooloose/syntastic)

~~~
Arnor
Thanks!

------
mratzloff
Previous discussions:

\-
[https://news.ycombinator.com/item?id=5600883](https://news.ycombinator.com/item?id=5600883)

\-
[https://news.ycombinator.com/item?id=5596422](https://news.ycombinator.com/item?id=5596422)

------
stcredzero
Many of the things he says he misses from Python, I would rather not have in
production code. Heterogenous dictionaries are often objects that should have
been, with no encapsulation and a high degree of implicitness that makes them
hard to refactor later.

------
pallinder
"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."

Could just load it into a map[string]interface{} and then just make sure he
does type assertion on the value before using it.

------
hvs
This is purely anecdotal on my part, but I've been working on a project for a
few months and I've been developing it in Go and it has just been a pleasure
to use. It's like C with the edges smoothed out using Python sandpaper.

------
Osmium
Is there a decent numpy/scipy equivalent for Go yet? By which I mean an easy
way to manipulate matrices, complex numbers perform discrete Fourier
transforms and the like.

~~~
kisielk
Nothing nearly as mature, but the project is here:
[https://github.com/gonum](https://github.com/gonum) and the mailing list is
here: [https://groups.google.com/forum/#!forum/gonum-
dev](https://groups.google.com/forum/#!forum/gonum-dev)

------
rlpb
Has anyone tried to integrate Go with Python?

Right now, optimizing Python code by replacing critical sections with C works
really well and isn't too hard to write or distribute.

How well would tooling around doing the same thing with Go work?

~~~
sprash
That won't help you much with concurrency problems, however "multiprocessing"
does.

~~~
TylerE
Well, it could, if your use case gets down to "pass an entire work unit in,
get a result back".

~~~
sprash
Indeed, but that would mean to write the majority in Go and glue it together
with Python instead of just outsourcing small performance critical pieces as
described by OP.

------
16s
_" No built-in type for sets (have to use maps and test for existence)... In
absence of sets, have to write your own intersection, union etc. methods"_

In my mind, a map is a set. They are both Associative containers. It's just
that the key and value can be different things in a map while in a set, the
key and value are the same thing.

Edit: I speak from a strong C++ viewpoint, but maybe Go is not like that (I'm
not sure why it would not be):
[https://en.wikipedia.org/wiki/Associative_containers_%28C%2B...](https://en.wikipedia.org/wiki/Associative_containers_%28C%2B%2B%29)

~~~
RHSeeger
By that logic, a map is just a list where every odd element is a key and every
even element is a value.

There are semantic differences between maps and sets and lists. Just because
you can use one to represent all the others doesn't remove the benefit of
having all 3 available.

------
robdoherty2
Any HN readers of this post have any similar experience?

I know the bright team over at bit.ly made a successful switch from python to
go-- anyone else?

The more I hear about go, the more I like it.

~~~
gtaylor
I'm working on a personal project that uses Python for most of the page
rendering and Go for the heavy lifting (receiving a large stream of data that
I have to process quickly and efficiently).

The ecosystem has a long way to go (compared to Python), but goroutines and
channels are a pleasure to work with. It's nice being statically typed again,
and I really like object composition versus Python's inheritance. Resource
usage for my cases is much lower, latency is much lower, throughput is much
higher, and my deploy/provisioning scripts are a lot more simple due to Go's
static compilation.

At my day job, we may start mixing in Go for background tasks that are a bit
too slow/inefficient in our current Python stack. I could also see it being a
good fit for some of our more high traffic HTTP APIs.

------
Arnor
Some of the items mentioned in that list are the reason why:

"The code you write with Go just seems to be correct."

e.g.

\- Having to always check errors (or at least explicitly ignore them) * By the
way, do this anyway. It's really nice when every error in your app is handled.
Since I've started with Go for a personal project, I've used a similar
approach in my _sigh_ PHP project so every error now has an explanation and
suggestion.

-Can’t have variables/packages that aren’t used so to test simple things requires sometimes commenting out lines

-Python is more forgiving. You can take slices of strings using indexes that are out of range and it won’t complain. You can take negative slices – not Go.

------
mjschultz
Here's a previous discussion of this post as well:
[https://news.ycombinator.com/item?id=5600883](https://news.ycombinator.com/item?id=5600883)

------
smegel
> The map/reduce idiom stinks in Python.

Actually multi processing has a reasonable implementation.

------
pekk
'migrating to Go' implies that Go has the same advantages as Python, which is
not really true.

------
DannoHung
I thought Go had union types? Do those not work... normally?

~~~
TylerE
Nope. I agree that it would be a good thing, and also cover about 80% of the
usecases for "true" generics as well.

------
callesgg
basicly most of the difrences that is mentioned comes down to that one of the
languages is compiled.

------
rwedf67
so you still trust the google compiler for your business critical apps do you?
haha

~~~
liveoneggs
I agree with this 100%

Who would adopt a NEW google-ism at this point?

~~~
jlgreco
Is C an "ATT-ism"?

~~~
liveoneggs
I keep looking for IEEE or ISO spec for Go and not finding it. I keep looking
for alternative compilers and can't find any.

Is there a defined standard library that you can count on for the next decade?

Maybe in 15 years when Go has outgrown its lock-in it may be worth
considering. At this point signing on with google is like playing russian
roulette.

~~~
jlgreco
> _I keep looking for alternative compilers and can 't find any._

Really??? How long did you look?

I call bullshit; you did not look. GCC is an alternative compiler. Go away
troll.

~~~
liveoneggs
gccgo is still from the same google-owned go project.

I'll gladly go away, fanboy.

~~~
jlgreco
It is a first class member of GCC, under the GNU project. There are no
possible concerns. I challenge you to attempt to articulate even one. No vague
"google pulls the plug" statements, articulate a _specific_ concern. Try it.
You idiot crybabies, seemingly primarily people who got butthurt at having
their hosted RSS reader pulled out from under them, never can.

You are either a troll or an idiot. Actually, I'm leaning towards both.

------
13b9f227ecf0
I keep seeing articles about Go where Python developers seem to be shocked to
discover that interpreted dynamically typed languages are very slow. This
wasn't obvious from the get-go? Practically anything not disk bound will be
many, many times faster in C++ or whatever.

