Hacker News new | past | comments | ask | show | jobs | submit login
What Python developers need to know before migrating to Go (repustate.com)
120 points by Nogwater on July 8, 2013 | hide | past | favorite | 111 comments



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


> 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)`.



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{}.


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

    switch x.(type) {
    // cases
    }


The parent post said "statically".


Does Go really not have tuples? (Aren't multiple return values tuples?)


It has multiple return values and syntax for assigning the results of a function that returns multiple values, but tuple values are not first class and the destructuring form is limited to calling a function and extracting its return values.


you can't monkey-patch functions into external libraries like you can with Python modules

You can add functions to existing types in Golang.

no preemptive multitasking, so one goroutine can wedge the entire program

That's pretty misleading. If all you write is go code, you can't "wedge the entire program" in Golang just from one thread. You could wedge a native thread if you were using C methods. Assuming you don't want to fix your broken code, you can just set GOMAXPROCS to something high and work around even that.

passing around arrays and structs is by value, leading to unexpected allocation and memory usage

Most developers pass pointers. Pointers are not really that hard in Golang, because there is no pointer arithmetic or undefined behavior.


Methods for a type have to be declared in the same package as the type.


Fortunately you can embed other people's types within your own type, thereby extending it.


Sure. But that's not monkey patching, that's inheritance.


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) 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.


> between chars (or "runes" WTF?) and integers.

"Runes" were the original name, as implemented in Plan 9 by the same folks, for what the standards committee later decided to call the relatively blaze term "Unicode codepoints"--and which are not quite the same thing as characters.

(In fact, I would say that the notion of a Unicode "character" is ambiguous to the point of uselessness--there are glyphs composed from several codepoints (base glyph + combining accents), which should be treated as one "character"; there are ligatures that hold single codepoints, but which semantically are multiple "characters"; there are stacking languages where one "character", representing a whole word, will be composed together from several codepoint "radicals"; while in other ideographic languages, each pre-composed idea-part is its own "character" and has its own codepoint; and so forth.)


> -there are glyphs composed from several codepoints (base glyph + combining accents), which should be treated as one "character"

The solution is to use Normalization Form C (NFC) (which combines accents with characters).

> there are ligatures that hold single codepoints, but which semantically are multiple "characters"

OK, so use Normalization Form KC (NFKC) (which splits ligatures, and combines accents with characters).

You're right that "length" of a unicode string is very ambiguous. Arguably, you shouldn't be able to call "length" without supplying an argument about what you are actually asking.


> 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.)


Plus, && and || are symbols which makes them stand out from variable names. This is, in my opinion, a benefit. Admittedly, though, I prefer {} to block delimiters over begin/end and their like.


That's 10 minutes where I could be... you know, living my life, man. Everybody knows what + does. You don't have to teach a high schooler that "if A or B" means "if either A or B is true". They just get it. But what the heck does "if A || B {}" mean?


Actually, you do have to teach most high schoolers (actually most people) what "A or B" means. The common usage reads that as "A xor B"


A very good point. I still think it's a big win if it makes it 1% easier for new programmers to understand.


I actually think "and" and "or" make it 1% more difficult for new programmers because it doesn't implicitly warn them about things like short-circuit evaluation and whatnot. "and" and "or" have a lot of nuances that experienced programmers take for granted that a new programmer won't know until they're taught.


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


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).


I don't think the argument is that people can't understand '&&' and '||', but that using 'and' and 'or' is a better choice.


So what do you do about the bitwise and and or operations. How should they be expressed?

Python expresses the bitwise and and or using the & and | characters, the exact same characters as Go.

And that also explains why Go chooses to use && and || for and the logical and or operators.


The code is much more readable if the bitwise operators do not look almost identical to the logical ones.


> 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.)


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.


I agree with you, but FWIW, if you're already used to C, then the cognitive overhead of && and || is probably negligible. Given Go's pedigree, that doesn't seem too surprising.


Thank you for expressing it so eloquently.


they are, unfortunately you need to have paid attention at school when they taught you logic operators


> In Go:

    len("нєℓℓσ") // 12, because there are 12 bytes
    utf8.RuneCountInString("нєℓℓσ") // 5, plz kill me i am an abomination
I'm not sure I understand your objection. Bytes and UTF8 characters are different things, and you can't abstract away the difference. There are also times, perhaps the majority of times, when you will need the byte count of a UTF8 string. That means you need at least two different length functions for strings and they need different names.

Shouldn't UTF8-specific things live in the utf8 namespace? Some programs won't need any string handling, after all, and it would be a waste to include code they never used.

Assuming you can allow the utf8 namespace as sensible, would you feel better if there was a RuneLen() function aliased to RuneCountInString()?

If you are that upset about it, then my suggestion is to explain your rationale and submit a patch[1] to provide the alias. It's not like it would be hard to code. Perhaps you might convince people and get it in the next release.

[1] http://golang.org/doc/contribute.html


I think the majority of the time you want the number of utf8 characters and not the byte count. In fact I have never wanted the byte count. If I did I would expect something like byteLen and Len. Not the other way around. You should be optimizing the common case, not the exception. Obviously I'm not a language designer so perhaps I'm talking out of my ass but I've heard this complaint A LOT.


Have you never had to indicate how many bytes you are sending over a stream, say in the Content-Length of an HTTP response? Have you never put strings into a byte buffer?

But that doesn't matter. Let's say you are correct: when working with strings, you more often want the rune length. It still wouldn't be the right decision, given the other design decisions of Go, because it would have needlessly complicated things with only arguable benefits. Let me show you what I mean.

The len() function works with a whole lot of things: strings, arrays, slices, maps and channels. For the first three, len() returns the number of bytes involved. This is because all three are backed by an array, and so sensibly have similar semantics. It would have violated the principal of least surprise for anyone who knew the language to have an array-backed storage not return a byte count. Both the language developers and the users of it would have to special-case strings, in code and in their brains.

Now, they could have decided to do it anyway, but then another surprise awaits. What happens when you take a slice of a string? Oh no, more special casing and more complication for everyone.

The Go developers do special-case where doing so would clearly be a win for their users. Consider range, which iterates by runes over a string, potentially moving the index on the underlying array forward by more than 1 on each pass. That is clearly going to be the most common usecase the user is going to want and so was worth doing. It also eliminates many of the usecases where getting the length of a string in runes would matter to you. Not all, but a lot.


> What happens when you take a slice of a string?

What happens when you slice a unicode string in Go is that it cuts multi-byte characters right in half, unless you get the byte boundaries just right. I know real programmers keep the byte boundaries for all the chars in all their strings in their head at all times, but for people like me this basically makes string slicing unusable for non-ASCII text.

Python somehow magically slices unicode strings without chopping characters in half.

In Python:

    s = "нєℓℓσ"
    s[1:4]  # "єℓℓ"
In Go:

    s[1:4] // "�є"


>Python somehow magically slices unicode strings without chopping characters in half.

You need a byte offset to slice a string, and it's impossible to convert from a Unicode rune offset to a byte offset without parsing the entire string up until that point. I'm not all that familiar with Python, but if the language works as you implied, it is basically doing this behind the scenes in common string processing tasks:

  1. The user uses some kind of pattern matching function or whatever to find where they want to split the string. Python returns a rune index.
  2. The user tells Python to go split apart that string along a rune index. It promptly begins parsing the string all over again until it finds the right byte boundaries.
  3. The language then actually creates the new string in between the byte boundaries.
Sure, a Python implementation could statically optimize this, but... why should it have to in the first place? That's fucking stupid and should be considered a language bug when it could be doing this:

  1. User pattern matches blah blah blah and gets a byte index.
  2. User tells their sane language to split the string apart at the byte index and it just does so.
>I know real programmers keep the byte boundaries for all the chars in all their strings in their head at all times

When the hell would you have to remember the byte or rune boundaries for characters in the first place? Why would you be slicing up a string with magic number indices? If you're getting indices from pattern matching functions, you shouldn't care whether they're in bytes or bits or nibbles, you should just be passing them on to your language's split routines (or whatever else you wanted to do). Unless, of course, you're the one actually writing low-level string processing routines, in which case rune offsets are far less useful than byte offsets for the reason explained above.

This Python "feature" seems to exist entirely to keep newbies from getting confused when they attempt to slice up strings in their REPL, for I cannot fathom a reason why anyone would write "s[1:4]" in production code. IIRC, Python was designed for pedagogy, so I'm not surprised that it would take on such a pointless implementation cost just to spare teachers from explaining why "s[1:4] gave me question marks"


You're right. You're not very familiar with Python. String slicing with numbered indices is used all the time. And you can slice more than just strings! It's one of the coolest features of Python and you're really missing out if your favorite language doesn't have that.

This might explain why my comments seem like heresy to you. I would point out that the OP is about Python programmers switching to Go.


>String slicing with numbered indices is used all the time.

Ok, so it (EDIT FOR YOUR BENEFIT: I'm talking about slicing strings with rune indices here, not slicing in general. Array slicing is a useful language feature, and, uh, it's not unique to Python or anything) is not just a language wart, but a fertile source of pointless inefficiency in everyday Python code, glad to know.

>This might explain why my comments seem like heresy to you.

You aren't challenging my beliefs or anything, I'm just trying to make you see that you don't understand how UTF-8 string operations work very well. If you did, you'd understand that Python is doing the exact same thing as Go here, but in a less efficient manner.


>Ok, so it's not just a language wart, but a fertile source of pointless inefficiency in everyday Python code, glad to know.

The fact that it's used all the time would suggest it's not pointless inefficiency, no? Maybe you should try Python before bashing it.

>Python is doing the exact same thing as Go here, but in a less efficient manner.

It's not doing the same thing. "�є" is not the same as "єℓℓ".


> This Python "feature" seems to exist entirely to keep newbies from getting confused when they attempt to slice up strings in their REPL, for I cannot fathom a reason why anyone would write "s[1:4]" in production code.

Dealing with a format where data elements are defined to be fixed length in characters that happens to be encoded in Unicode?


> Python somehow magically slices unicode strings without chopping characters in half.

Well, that rather depends on what you mean by "character" and "in half".

    >>> s = u're\u0301sume\u0301'
    >>> print s
    résumé
    >>> len(s)
    8
    >>> for i in xrange(len(s)):
    ...     print s[i]
    ... 
    r
    e
    
    s
    u
    m
    e

    >>> print ' '.join(s)
    r e ́ s u m e ́


> Have you never had to indicate how many bytes you are sending over a stream...

I have and I generally like the syntax to be more explicit (since I so rarely work in bytes): string.getBytes().length

You make all fair points, and I guess it is my opinion that varies then but I think the rule of least surprise would involve returning the rune count for both strings and string slices. Also, wow, range iterates over runes but len returns byte count. That's messed up.


Aside from API, there's a convincing performance argument to have len() return the byte count rather than number of utf8 characters.

The implementation of strings in Go is a 2-word struct containing a pointer to the start of the string and the length (in bytes). Under this implementation, len(s) is O(1) and RuneCountInString(s) is O(n). It makes sense to have the default case also be the fast one, particularly since people appreciate Go for its performance.

Alternatively, you could store the rune-count in the 2-word struct to reverse the above runtimes. However, this is detrimental for the common operation of converting between []byte/string as well as writing a string to a buffer. Both of those operations are a simple memcpy with the actual Go implementation, but would be O(n) using this alternate implementation.

Perhaps you could make it a 3-word struct that contains both byte-length and rune-length; Then all strings take up additional memory as well as requiring more overhead when used as function arguments.


Why not a 2-word struct with the rune count instead of the byte count? There's zero performance cost for many strings because the rune count is known at compile time. For the rest, most strings are too short for Big-O analysis to be relevant and I would guess (enlighten me if I'm wrong) that the cost of computing the bounds of each character is negligible on a modern processor. Multi-byte chars in a string are going to be adjacent in memory, adjacent in cache, and therefore trivial for today's not-at-all-instruction-bound CPUs. Again, correct me if I'm wrong.


It is very seldom that you really want to deal with a string as an array of runes. (If actually you do want to, Go makes it fairly easy: Just use []rune rather than string.)

Consider a simple string: "école". How many runes does it contain? Possibly five:

    LATIN SMALL LETTER E WITH ACUTE
    LATIN SMALL LETTER C
    LATIN SMALL LETTER O
    LATIN SMALL LETTER L
    LATIN SMALL LEtTER E
Possibly six:

    LATIN SMALL LETTER E
    COMBINING ACUTE ACCENT
    LATIN SMALL LETTER C
    LATIN SMALL LETTER O
    LATIN SMALL LETTER L
    LATIN SMALL LEtTER E
If you normalize the string you can guarantee you have the first form, but not every glyph can be represented as a single rune.

Fortunately, you generally don't need to deal with any of this. If you're working with filenames, for example, you really only care about the path separator ('/' or '\' or whatever); everything else is just a bunch of opaque data. You can write a perfectly valid function to split a filename into components without understanding anything about combining characters. When you're dealing with data in this fashion, you rarely if ever care about the number of runes in a string; instead you care about the position of specific runes.


Thank you for the explanation! Converting to a rune slice and back does give me the behavior that I wanted. It still looks butt ugly to me, but at least it works.

In Go:

    fmt.Printf("%s", string([]rune("нєℓℓσ")[1:4]))
    // єℓℓ
In Python:

    print("нєℓℓσ"[1:4])
    # єℓℓ


You almost always need the byte count for protocols, buffers and stuff. For user-interfacing use-cases (e.g. editors) you probably want the glyph or grapheme count, not the rune count. Please remember, runes / code points, graphemes and glyphs are different things:

http://www.icu-project.org/docs/papers/forms_of_unicode/


Have you spent much time in C? Go is directly descended from C, not Python. Its requirements are different.

- If you are passing a number of related arguments, often a struct is a better data structure than default or named parameters.

- I am ambivalent about panic/recover, but have no problem with the rest.

- I do tend to agree that "and" and "or" would be more readable, but it's such a minor issue.

- Regarding your UTF-8 example, I imagine the Go authors believed most Go users would be spending more of their time dealing with bytes than characters. Go is not a language optimized for text manipulation, it is optimized for byte manipulation, like C. This is apparent in the lack of effort put toward optimizing the regular expression engine to date.


> explains that leaving out overloading is "simpler", meaning _simpler for them_.

This also means your program code is simpler, and therefore, faster.

Function overloading usually means virtual method tables, and therefore indirect method calls. Depending on how deep your inheritance / overloading structure is, these vtables can get really messy.

(I had a class in university where we were given a C++ UML class diagram, and told to draw the vtables that resulted when one instance of a subclass was instantiated.)


Function overloading can be accomplished by name mangling at compile time.

  PROGRAMMER SEES        INTERNAL REPRESENTATION
  foo(int a, char b)     foo_int_char
  foo(int x)             foo_int


He did not mean overriding (methods in derived classes), but overloading (functions with the same name). You can resolve the latter at compile time, no indirection needed. For example you can have two overloaded functions println() and println(String).


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


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.


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?


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/


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?


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.


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


But if you do use a map as a wrapper, use map[keytype]struct{} . That way the values don't need any memory at all, struct{} is for free.


The real reason is almost always "We didn't feel like it. So =P"


In Java, sets are merely wrappers around a map that maps to a dummy. I guess Go just left off the wrapper.


A wrapper is totally fine really, actually better in some cases (see later). It still allows the programmer to map his intentions directly to the code, and make that intention directly visible to the reader. This adds to the "user experience" for the programmers.

Agreed that such wrappers are then easily built by the programmer himself. But then comes the added pain of including those definitions in everywhere within a project and in-between projects. They become one more dependency to handle.

Then come these wrappers or even whole data structures from third-party libraries. Nearly in every case I see, there is some impedance matching issue with some other libraries, requiring glue-logic to convert from one format to another. [Edit: Plus the added licensing/cost issues for those libraries.]

If a set is just a wrapper around some more generic data structure, it is OK to implement it like that in the library to avoid duplication of code in that library. However, by not making that wrapper, the system is resulting in much more amount of duplicated code in the user space and now with the mentioned impedance mismatch or with weak mapping of programmer's intentions to the code.


CPython's sets are implemented the same way.


A map is a set. In a map, the key and value can be different things. In a set, they are the same. That's the only difference. They are both associative containers.


So what? Got to start isolating interface from the implementation. That implementation inside has overlaps does not mean the interface should be compromised. The latter needs to be designed according to the common needs of the user (here, programmers) rather than the implementation alone. Think "user experience" people!


You asked why they would do this. I answered your question. Maps are sets. And by implementing map, you can use it as a map or a set. Perhaps you're not looking for an answer to your question?

Say I implement log, but not log2. If you understand what log is and how to use it, you have log2. If you don't understand this, you ask why log2 is not provided.


I think I do understand what you are saying. But then, by the same token, so many things are not needed in a programming language. C++ for example has often being criticized for not having a power operator (a^b). Why not just work with a Turing machine (simulated on a computer), then you have everything.

It is not just about having it or not having it. It is also about user experience. Why should I write log(x)/log(2) assuming that is a commonly used operation such that the library could have provided me with simply log2(x)?

Just yesterday there was an user experience related article on confirmation vs. undo. The message was that if most of the users are likely to take the action, then undo is better than confirmation, and if most of the users are unlikely to take the action, then a confirmation is better.

While it is bad to provide every option to the user, it is also just as bad to miss the options that the users commonly use.

The real question then is if a set is commonly required or not. I believe it is used often enough.


It's like some people don't understand that an API is an "interface" and simplifying that interface is a boon to productivity, readability, DRYness, etc. All your points are spot on and its absurd that some people don't get that in this day and age.

"Abstractions are useless, lets all just program with cmp and jmp statements"--seriously folks, have we not learned anything?


Indeed.

What I hate is that even after having a good understanding of software development and computer science fundamentals, and having a good picture of the solution to a given problem, I still cannot today program without having to perform multiple Google searches, reading Stack Overflow messages, etc. to deal with what should be trivial stuff.

Just for example, if I were to need a set, I would search for "set" in Go documentation. If the set itself is not included, on the very least the documentation should talk about what should I do instead. But they won't even have that in there. Result: Few more Google searches.


To be fair, Go includes a heap, list, and "ring" (circular doubly-linked list).

I agree that Go should include a Set type modeled after its List. Sets are simple and there's really just one way to implement them. My own is less than 40 lines; a simple set of tests are about 60 lines.

For trees, graphs, etc. I do think it is fair to establish these as the domain of the community. These are more complex, and there is more variety.


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.


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.


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 :)


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


Thanks!



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.


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


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.


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.


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


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


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.


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?


Haven't tried any of them, but I remembered there are some, so after quick googling:

https://github.com/sbinet/go-python

https://github.com/qiniu/py

https://github.com/qur/gopy


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


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


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.


uWSGI with CPython and Go workers, with RPC each other.

http://uwsgi-docs.readthedocs.org/en/latest/Go.html


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.


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.


I don't think they did an entire switch over.

"We identified early on that Go had all the makings of a language that could supersede some of the places we would have traditionally turned to C and some of the places where we wanted to move away from Python."


I've been messing around with it for some internal infrastructure. I like it so far. Excellent performance characteristics, and the tooling is supremely good, making the dev workflow much less painful than traditional compiled languages.


I've been using Go for my company's backend api which communicates with Youtube movies, amazon movies, Netflix, etc and it seems very well suited to the work.


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.


Here's a previous discussion of this post as well: https://news.ycombinator.com/item?id=5600883


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


> The map/reduce idiom stinks in Python.

Actually multi processing has a reasonable implementation.


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


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


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


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


If you have gcc installed, you can build the Go compiler from source and that build process is really trivial.

So you have the source code for the compiler and source code for the standard library and the source code for any package you might decide to use.

Now obviously you'd need to build a pilot to test all of these those components.

But other than the risk of that pilot not working as expected, where else is there a risk and how is that different to any other technology?


I agree with this 100%

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


Is C an "ATT-ism"?


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.


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


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

I'll gladly go away, fanboy.


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.


gcc is owned by Google? Someone should tell the gcc folks and Richard Stallman that.


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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: