People have been poopoo-ing Go lately on HN but let me tell you after using it in production for over a year. It really makes developers life easier. Why?
1) Error handling, Give you ability to impose defensive practices making network or another other I/O failures or unexpected responses from external or internal calls easy to handle.
2) A lot of errors can be caught at compile time. Which means less errors in runtime.
3) It so simple that all of the build in functions and syntax can be expressed in less than 16 lines. Makes reading your code and anyone else code very very easy. Also FMT is sick.
4) Dead simple concurrency.
But all this has still not helped me push Go as the goto lang at the company I work for, why? Sometimes you work with people that just don't want any change.
Give Go a try you'll be shocked how well its designed.
Go is often judged (and praised) based on it's concurrency. But I use map/filter/reduce, etc. far more often than I use concurrency. So no matter how great the concurrency story is, having to use for loops all over my code makes my life much worse.
This was actually fairly heavily discussed on the Golang mailing list a few months ago[0]. For now I believe the designers of the language would rather keep things as simple as possible. For something that can be done with a fairly simple for-loop, they would rather have you write that out. If there is certain functionality that requires a complex amount of code, the would consider adding either a package to help or changing the language if needed.
Loops make your life worse, really? Loops are trivial code that are nearly impossible to screw up. Writing a loop and writing map/filter probably take nearly the same time. If this is the biggest problem you have in coding, you're luckier than most.
How do you mean exactly? Go has an iterable for map, slices, arrays, strings, channels with the "range"[0] keyword. The values returned by range are copies of whatever is in the structure so they should be immune to mutation (unless you're messing with pointers).
He means that what you actually want to do is modify some state outside of the loop when you're iterating, which means that your loop doesn't provide a "safe" context where you know what to expect.
Are you sure you're modifying the correct outside variable ? Are you sure you really are modifying it:
bar[i] = f(foo[i])
and not creating a new one:
bar[i] := f(foo[i])
? Are you sure you're not also modifying another variable that you didn't know was "linked" somehow ?
Given the direction Go has taken, it would make very little sense to introduce functional programming bits. But you must admit that the immutability/lack of side effects of the FP gives you a lot of assurance on what to expect.
I think you need to provide an example of what you're trying to say, as the syntax you showed above is not valid. the := operator is for defining a new variable, not for creating a new instance of some type. The := operator is just shorthand.
foo := 5
is shorthand for:
var foo int
foo = 5
the "range" keyword over an array gives you the index and the value at that index. If you don't need the index or the value, you can put a "_" in it's place (to save on the allocation).
You'll notice that foo[i] is still printing "0", because range always creates a copy of the object assigned into v. Unless you start using pointers, you'll never have mutation issues.
If composability, avoiding mutation, and eliminating loops are the focus of what you want from a language, then Go is definitely not trying to solve your problems.
But maybe, rather than just carping, you should wait until you really understand why Go is trying to solve the problems that it is actually trying to solve. Because I don't think you do understand that yet.
Go is trying to solve the kinds of problems you run into when you have a multi-million-line code base that you have to maintain over two or three decades. At that scale, you get new problems - not just more of the same old programming-in-the-small problems.
I'll give you this much, though: Loops are easier to screw up than the grandparent seems to recognize.
Mutation is a problem that every program must deal with. Map/filter/reduce and company are just a good way to isolate mutation. Your entire application doesn't need be functional to benefit from some functional behavior.
Likewise, composability improves readability and isolates code into small parts that can be assembled. This is beneficial to large applications as well.
You seem to indicate that concurrency is the only problem worth investing in with large applications but they are not mutational exclusive. Erlang does a good job of both, for example.
I never said that concurrency was the only problem with large applications. I never even meant to imply it.
For example, one of the big problems is circular dependencies. Go solves this by explicitly prohibiting it - your dependencies must form a directed acyclic graph. You therefore have to work out a solution the moment you would want to introduce a circular dependency. You can't introduce even the first one. That means that you can never build up the kind of nightmarish hairball that large projects often turn into.
Is it painful to have to prevent circular dependencies all along the line? Certainly. But it prevents more pain later.
Now: Do I know that functional programming, map/filter/reduce, and avoiding mutation cause problems at scale? No, I don't. On the other hand, I doubt many projects have been built using FP at this scale, so one can't assert that FP will scale this far.
What are some other things? Having no circular dependencies doesn't seem very novel or something that requires much of a tradeoff. Although I will admit I am more of a fan of it after having used it (F#, which requires tight opt-in to mutual references), than before having used it (at which point I would have said "just don't do that").
1) Error handling, Give you ability to impose defensive practices making network or another other I/O failures or unexpected responses from external or internal calls easy to handle.
2) A lot of errors can be caught at compile time. Which means less errors in runtime.
3) It so simple that all of the build in functions and syntax can be expressed in less than 16 lines. Makes reading your code and anyone else code very very easy. Also FMT is sick.
4) Dead simple concurrency.
But all this has still not helped me push Go as the goto lang at the company I work for, why? Sometimes you work with people that just don't want any change.
Give Go a try you'll be shocked how well its designed.