Why I Don't Like Golang
teamten.com
teamten.com
The standard library is very nice, but the language constantly feels like it's working against me or I'm having to circumvent some intended feature (no generics, while not a problem in the beginning, has continually worn down on me). Besides that, reason 9 is a huge nuisance which needs to be resolved,
You know, "I just changed this little thing and I want to see what happens".
If you setup your text editor to execute goimports on save, it won't happen, because the import will already be removed.
> If you uncomment out that line of code and re-run goimports, will goimports automatically re-add the correct import statement every time?
Most of the time, yes, but not every time. It works well for the standard library and when the last segment of the package name is enough to identify the package.
2. This is called "structural typing" and it's one of Go's greatest features. It looks like the author prefers "nominal typing". Both approaches have their pros and cons. See https://golang.org/doc/faq#implements_interface.
3. Go by design doesn't have exceptions. See https://golang.org/doc/faq#exceptions. github.com/kisielk/errcheck can be used to make sure errors are checked everywhere (but I agree this is not ideal).
4. I don't get that part. Sounds like nitpicking to me.
5. I don't get it either. If there is a "collision", you can use an alias. And I personally don't like having to repeat fully qualified package names everywhere. On this topic, I prefer Go's approach to Java.
6. Go has been designed to automatically generate code! A lot of tools do that all the time, the best example being gofmt. The compiler being strict is more an advantage than a liability for this purpose. But I agree with author about the issues created by packages sharing the same default name. Would be curious to know the advice of the Go team on this.
7. I mostly agree about missing the ternary operator, sometimes. But I don't miss the code I read in other languages that abuse it. I'm 50/50 on that.
8. I agree about sorting being "clumsy". This is being worked on at https://github.com/golang/go/issues/16721.
9. I agree about Go not providing anything builtin or well-known for dependency versioning, but I completely disagree about vendoring. See https://golang.org/cmd/go/#hdr-Vendor_Directories.
10. Missing generics is probably the most talked topic about Go. I miss them sometimes. I keep hoping Go solves this one day. Here is Russ Cox explaining why Go doesn't have generics today: https://news.ycombinator.com/item?id=9622417.
"This was not an easy design decision. We spent over a year struggling to define the notation to specify an identifier's visibility. Once we settled on using the case of the name, we soon realized it had become one of the most important properties about the language. The name is, after all, what clients of the package use; putting the visibility in the name rather than its type means that it's always clear when looking at an identifier whether it is part of the public API. After using Go for a while, it feels burdensome when going back to other languages that require looking up the declaration to discover this information."
Source: https://talks.golang.org/2012/splash.article
Must be noted that any identifier that doesn't start with an uppercase letter is not exported. This makes possible to use an underscore to mark unexported identifier and still use uppercase letters (like _Name or _SOME_CONSTANT), which is a common practice in many programming languages (like Python). This is not idiomatic in Go, but it's possible.
That's what I do too, but I don't change names. I use "export" declarations for packages, which are completely orthogonal to what the symbol represents. Less naming problems. The capitalization thing would be in the "Meh" category for me, that's all.
This allows for example to make a symbol exported in different packages, or take separate code and provide a unified facade package. But most of the time you just need to define the public interface of your code and this is quite easy.
Generics have been around for decades in real programming languages, outside of a research setting. His post just makes it seem like a proper type system with good inference and generics is over all the heads of the people who work on Go.
? It literally has built-in support for a vendor directory.
Great cover image though, I lol'd.
That said, there are some high level ergonomic features to the language that make it seem much more high level than it is.
Still, if you're looking for a language with greenthreads and a GC, Rust is not that.
That said, coming from Python, I sometimes miss its expressiveness. But when I switch back to Python, I miss Go "straightforwardness".
Use Go for small to medium server side systems. A lot of the issues mentioned by OP are related to scaling (in terms of codebase) stresses that Go is ill equipped to address. In the small scale, Go works like a charm.
Use Go for large server side systems that compose via IPC (of whatever flavor). Lots of processes mean lots of small scale Go applications (so see above).
Strongly consider Go for server side systems where 'Green Thread/Fiber/lighweight threading' is an architectural requirements. Also consider Erlang/Elixir and possibly Node. If IPC composition is also a match (see above) then Go is a serious consideration.
You want a compiler in loop writing (relatively) portable cmdline tools. Go is a serious candidate here as well.
I suspect a subset of the Go angst is due to philosophizing about a language that proudly wears an anti-intellectual badge on its cute furry coat. Stop doing that, accept it for what it is, and sure enough it is very useful and capable in its own niche.
Python perl php ruby are interpreted so despite best efforts by their conmunities they simply aren't as fast ( though their libraries are nice) and often fast enough.
Go seems to straddle the space between the Lower and higher levels. Kinda like Java if it compiled to native. The one language that I see in the same space that is evolving fast is swift.
But the rest are either (A) it doesn't work the way I want it to work or (B) I haven't read the manual and it's your fault.
It's 2016, Generics are not some controversial "personal preference" and neither are badly designed APIs.
http://www.tiobe.com/tiobe-index/
edit: not saying generics are bad, but not having generics in golang was a design decision not an oversight.
How many of them are 2016 programming languages, solving 2016 problems -- as opposed to 2 and 3 and 5 decades old languages designed in another era?
(Not to mention that even some 3+ decades old languages have generics...)
>edit: not saying generics are bad, but not having generics in golang was a design decision not an oversight.
I think in some languages design decisions and oversights are not contradictory.
So not supporting generics is a design decision and not always a bad one.
I'm not sure about this, I believe it's a solved problem.
Languages have had them for decades, and lots of different avenues have been explored. Neither Java nor C# (and those are mainstream pragmatic languages, not experimental academic affairs) have particular issues with their (different) respective Generics implementations (except the obvious tradeoffs I mean -- but it's not like programmers or their compiler writers are strugging because of them in any way).
They are also quite easy to add to a language (even hobbyist languages have them) -- I'm not sure why you say that "very few languages attempt to implement it".
The big two used by tens of millions (Java and C#) have them, C++ has them, F# has them, Swift has them, Scala has them, Delphi had them, lesser used languages like Ada, Julia, Haskell, D etc have them. Heck, almost all modern mainstream languages have them.
"Proper generics" is a red herring put forth by Pike, where its would only be OK to have generics if it came without any tradeoff at all, where tradeoffs even include the compiler being harder to write.
Yeah, I don't think they can magically created pain free either. I do think they solve a lot of pain where it matters: for the programmers.
>And people are still arguing whether generics in C++ do more harm than good (i.e. complicate debugging).
That's because generics in C++ come with all the template baggage and a full turing-complete and complicated scheme to work with them. There's no need to go there.
This. To further add to this, an argument against generics used to be worries about showing compile times, but that didn't stop rewriting the compiler in Go or implementing SSA. Go's compile times are still much slower than they were.
Point being that generics aren't seen as important, not as being too difficult to implement correctly.
I think the trade offs in those cases were pretty clear. The switch from c to go was made so that compiler development would be easier, and indeed you could well argue that it was a big enabler in work like reducing GC pause times. Similarly, one of the big reasons for switching to the SSA back end was to enable improved optimisations down the line. I think the results of this work are fairly clear already: in 1.7 binaries are generally smaller than 1.6, sometimes by as much as 20-30%.
I think the trade-offs for generics are less clear. Compile times may increase, they'd add complexity to any implementation and, perhaps most importantly, they'd add significant complexity to the language. On the other hand, they make certain classes of problem substantially easier and significantly simplify some APIs.
No doubt it's possible, the question is can you do it without adding lots of language complexity and corner cases?
If it's being used in 2016 (on new development), it's solving 2016 problems. What year it was designed is irrelevant.
That's not because either is particularly suitable for today's needs (or even 2 or 3 decades ago needs), but because the industry hasn't managed to come up and invest in valid candidates -- plus the whole backwards compatibility baggage.
It's more of "the devil you know", "this language has all this libs we can reuse", "this language has 3 decades of tooling" etc that determines "suitable for use", instead of any inherent value in the language (syntax/compiler).
Just ask Alan Kay...
try { stuff() } exception(Exception e) { }
I would consider complaint #6 a B.Explicitly ignoring errors is a feature that you sometimes need. The equivalent in Go would be to write:
_ := db.Exec("DELTE FROM item WHERE id = 2")
... which could be written for bad reasons too, like in Java. However, nothing prevents from writing: db.Exec("DELTE FROM item WHERE id = 2")
... which would be like: stuff()
Both of those could be written either intentionally or by error, maybe because someone did not read the documentation correctly. However with exceptions, even if the exception is not handled, at least it is caught.So Go by design does not use exceptions, which is respectable choice. However, it is supposed to be different from C by making it hard to ignore errors. And the example from #3 is the absolute contradiction of that philosophy. I'd expect all return values to be checked for usage.
Go could take example from Ada in that regard.
-----
For #6, what would be the solutions to OP's example problems?
Isn't that the opposite? conventions (even ugly ones, or annoying ones) help with consistency across many developers or large projects.