I've heard that claim a lot, but I don't really see it. I'm in the process of working on a Go AppEngine prototype at Google. Not huge, but large enough that I get a feel for the language. I like it, but it's not at all like Python for prototyping. Things that I really miss, in a prototyping context:
1. The ability to dump large amounts of untyped data on your app and pull out only what you need. I get back a JSON response from backends with hundreds of fields. In Python I can just parse it into a dict of arrays and pull out only what I need. In Go I have two options: parse into a map[string]interface{} and then use a whole lot of type assertions when I want to actually manipulate the values, or parse into a user-defined data type that pulls out the fields I need. I've opted for the latter, but since the JSON data structure is nested about 6 levels deep, that's a lot of types I have to define before I can do anything.
2. List comprehensions. So much of prototyping is basically "Munge this data type and compute something. No, actually, munge this whole list of data types and compute a list of somethings." That's a one-liner in Python, about 4-5 lines in Go. It adds up.
3. Awkward append syntax. For such a common operation, it's awfully verbose (and confusing, until you get used to it and understand why you need to reassign the result back to the slice you're appending to).
4. Error handling. In prototyping you usually just want to ignore errors on the first pass through and print a traceback. Go explicitly discourages this and makes you check the return value. And you can't even write a type-safe utility function that takes a function that returns (result, err) and panics if err is non-nil, because of the lack of generics. (The return type of such a function would depend upon the function that's passed into it, which you can't express statically.)
5. Pass-by-value defaults. In Go structs are value objects, which mean they're copied when passed to functions or assigned to variables. This is a reasonable design choice, but means that you need to think about whether you want a value or a pointer before writing the code. And if you screw up or forget to change it, your local modifications to the object are silently ignored. When I'm prototyping, my attention is usually on the problem domain and not on the language, and there've been several times I've messed up because a function suddenly needs to start modifying its argument but it was passed in by value and I forgot to change it.
To be clear, I like Go a lot as a production language, and I wish that the large C++/Java systems I maintain were written in it. But it doesn't really come close to Python for prototyping in my experience. I'm a little surprised after hearing many glowing testimonials about how Go is just as productive as Python and just as fast as C++; I would still say there's at least a factor of 2 difference in productivity. I see Go as the new Java (and also the anti-Java, in terms of design decisions they made). It's simple enough to learn quickly, it's "good enough" in performance to be used in production systems, and its design tries to encourage unskilled programmers to not screw things up too badly. On all these counts I think it's strictly better than Java. But I feel like for people that are willing to use a multi-language solution, Python + C(++) is strictly better for most of the various types of programming you'll face in building a large system. Python beats Go for scripting, Python beats Go for prototyping, Python beats Go as a config language, C++ beats Go for high-performance computing, and C++ beats Go if you need to be close to the machine. And with Cap'n Proto one of the slowest and most annoying parts of maintaining a large multi-language system (re-marshaling your data structures across the memory boundary) goes away.
What I'd really love is a way to use Python as a prototyping/scripting language and Go (instead of C or C++) as the underlying production substrate, but their runtimes are pretty incompatible.
+1 for lots of interesting points. Regarding the benefits of Python, I definitely agree. For writing my own scripts, small utilities, one-off data processing jobs (turn this CSV file into a big JSON object, etc.) and all the little, daily automation tasks I run into, it's hard to beat Python, and I'm usually surprised at how fast it is. I don't plan to give it up as my "everyday carry" Swiss Army Knife language.
For writing apps for the server, where it will keep running 24/7 serving thousands of people, I think I'm okay with giving up what you estimate to be about a factor of two in productivity for the performance gain, but I wouldn't give up the order of magnitude productivity difference needed for C++ to gain another factor of two in performance (vs Go) unless my code had to serve millions. I don't see that happening anytime soon, so Go as the new, improved Java (I see it that way, too) still seems like the sweet spot for server coding for me.
"And if you screw up or forget to change it, your local modifications to the object are silently ignored. "
Since I started writing Scala I got used to immutable data and the reverse happens to me when coding in imperative style in other langs; that I pass something and it gets "locally modified" feels awkward. Preposterous even.
Regarding Go and the "also the anti-Java" part: I really don't think so.
They have made some decisions that seem to me a reaction to c++ and that at least is similar to Java. Some of them seem simplistic not simple: for example "There is no inheritance!" (one one one) but I really don't know how implicit structural subtyping will work out in the long run.
What I really envy from Go is the "compile and link to one executable" from an ops point of view.
I actually really like immutable data - I was (and still am, when I don't have to get work done) a big fan of Haskell. The problematic part is when you have a language that encourages an imperative programming style, and yet passing an object by value is only one character off from passing it by reference.
1. The ability to dump large amounts of untyped data on your app and pull out only what you need. I get back a JSON response from backends with hundreds of fields. In Python I can just parse it into a dict of arrays and pull out only what I need. In Go I have two options: parse into a map[string]interface{} and then use a whole lot of type assertions when I want to actually manipulate the values, or parse into a user-defined data type that pulls out the fields I need. I've opted for the latter, but since the JSON data structure is nested about 6 levels deep, that's a lot of types I have to define before I can do anything.
2. List comprehensions. So much of prototyping is basically "Munge this data type and compute something. No, actually, munge this whole list of data types and compute a list of somethings." That's a one-liner in Python, about 4-5 lines in Go. It adds up.
3. Awkward append syntax. For such a common operation, it's awfully verbose (and confusing, until you get used to it and understand why you need to reassign the result back to the slice you're appending to).
4. Error handling. In prototyping you usually just want to ignore errors on the first pass through and print a traceback. Go explicitly discourages this and makes you check the return value. And you can't even write a type-safe utility function that takes a function that returns (result, err) and panics if err is non-nil, because of the lack of generics. (The return type of such a function would depend upon the function that's passed into it, which you can't express statically.)
5. Pass-by-value defaults. In Go structs are value objects, which mean they're copied when passed to functions or assigned to variables. This is a reasonable design choice, but means that you need to think about whether you want a value or a pointer before writing the code. And if you screw up or forget to change it, your local modifications to the object are silently ignored. When I'm prototyping, my attention is usually on the problem domain and not on the language, and there've been several times I've messed up because a function suddenly needs to start modifying its argument but it was passed in by value and I forgot to change it.
To be clear, I like Go a lot as a production language, and I wish that the large C++/Java systems I maintain were written in it. But it doesn't really come close to Python for prototyping in my experience. I'm a little surprised after hearing many glowing testimonials about how Go is just as productive as Python and just as fast as C++; I would still say there's at least a factor of 2 difference in productivity. I see Go as the new Java (and also the anti-Java, in terms of design decisions they made). It's simple enough to learn quickly, it's "good enough" in performance to be used in production systems, and its design tries to encourage unskilled programmers to not screw things up too badly. On all these counts I think it's strictly better than Java. But I feel like for people that are willing to use a multi-language solution, Python + C(++) is strictly better for most of the various types of programming you'll face in building a large system. Python beats Go for scripting, Python beats Go for prototyping, Python beats Go as a config language, C++ beats Go for high-performance computing, and C++ beats Go if you need to be close to the machine. And with Cap'n Proto one of the slowest and most annoying parts of maintaining a large multi-language system (re-marshaling your data structures across the memory boundary) goes away.
What I'd really love is a way to use Python as a prototyping/scripting language and Go (instead of C or C++) as the underlying production substrate, but their runtimes are pretty incompatible.