There's a difference between using a struct to represent concepts like program configuration or grouped function parameters, and shoehorning OO-native design concepts like the decorator pattern that need inheritance into a language that doesn't support dynamic dispatch. Much of the bad Go code I see comes, yes, from overusing abstractions and lots of copy-pasting, but most of that comes from trying to fit square pegs like OO design into Go's round hole.
I think the "object"-less OO tag is a bit overblown. Structs are objects. Just because Go creators didn't choose to name them that doesn't mean there's a fundamental difference between Go structs and other languages' objects.
Go is a crap programming language with a good runtime.
- No generics
- No true buy-in on the idea of a structural typesystem
- No sumtypes
- An anti-intellectual fanbase
- Exceptionally painful error handling
- Zero ability to abstract anything out without relying on the reflection package which leads to brittle and slow software.
They didn't do everything wrong though.
- It's great that they have a spec (I wish it came with formal semantics, but still)
- It compiles quickly and is easy to analyze (so tooling w.r.t. LSP is great and exceptionally fast)
Anyway, I never find programming in Go fun, and I find Rob Pike to be obnoxious. OK, that last part might just be me projecting how obnoxious Go is onto him.
You're not supposed to use struct tags, type aliases, "interface {}" or reflection either... that's a lot of features Go developers "aren't supposed to use"... Why are they here then?
If you considered them it's even worse - by keeping the language simple you've made it more unintuitive and less readable for the programmer. IMHO the primary beneficiaries of Go are the compiler writers, not the programmers having to read and write source code.
Your example is not the same, this is just a C-style single method. The whole point of my example was using Go's own sample source code to showcase the hacks needed around structs to get around the deficiencies in not having classes. The resulting struct method signatures are ugly, verbose and unintuitive - it's not nearly as readable and wrist friendly as grouping them in a single class definition.
In following this pattern the defer keyword is a magic method that doesn't visually demonstrate its behaviour - compare that with C#'s using statement which does.
After working with it for a year, these are the things I don't like about Go:
1) No constructors. When I create a struct, without a constructor, I can't be 100% if certain fields are populated or not. With a constructor, I could force this. With a large number of people working on a code base, you can't assume anything, unfortunately, but without a constructor to force exact data in a struct, it makes it more tedious to be sure.
2) Error handling is ugly and tedious. Not being able to get the type of an error makes it a lot more inconvenient. At least in our codebase, errors are almost string parsing, it's ridiculous.
3) Nil map vs empty map is a very strange thing to keep in the code. Why even allow this distinction?
4) Named return parameters are really stupid. This is another thing that doesn't fit the philosophy of what I understand Go to be. It forces a bunch of verbose opinionated rules on us, but then allows named return parameters which causes confusion.
5) It's very hard to tell the difference between package names vs structs. Luckily Gogland allows you to change the color for package names so this helps me out tremendously, but there should be a better way to differentiate without relying on your IDE.
Overall it's okay but nowhere near perfect and has some really weird deficiencies. The company I work for uses Go with dependency injection which I hate and I think is very ugly but a paycheck is a paycheck.
IMO, Go is capable of supporting OOP style code, but is not an OOP language. Coming to Go from more dogmatic OOP languages is such a breath of fresh air. If you just need a struct, you can have a struct. If you want a package scoped standalone function, you don't need to invent some made up "class" to attach it to. As the article shows, you can implement OOP style code and use OOP paradigms when they make sense. With Go, they emerge more naturally from the code as you are not trying to force them in from the start.
These are probably trivial things to a lot of people but after being brought up on Java, and working in rather OOP-heavy frameworks for years, it's liberating.
> This is a discovery process, I'm writing this document to help myself understanding golang and maybe help others.
First: I took a brief look through this, and I didn't see anything that jumped out as wrong. It's a pretty comprehensive document, especially for someone who says they're just starting out, so kudos to James for writing it!
That said, from my experience in teaching Go classes and workshops for beginners, comparing embedding to inheritance is usually a bad idea. It's not that there aren't similarities, but in my experience it prompts new Go programmers to write unidiomatic Go code when they think of embedding in that way. They end up embedded structs the way they'd use inheritance in object-oriented languages, and since Go isn't really intended as an object-oriented language, it makes for unidiomatic code.
The main use cases of inheritance in OOP are accomplished by interfaces in Go, not struct embedding. But at the same time, the main benefits of embedding come from embedding interfaces - embedding structs is almost an afterthought in the language. In fact, I tend to advise people against embedding structs altogether. There are a few cases where it's worthwhile to embed structs, but the use case for embedding interfaces is much more powerful.
My advice for Go beginners: use interfaces more than you think you need to, and forget that struct embedding is even possible. This rule of thumb helps to write more idiomatic Go code when you're just getting started, before you have a feel for what that really means.
Yeah, I love that Go uses structs. Go is my favorite language, but it still has lots of rough edges, like no generics or sum types. If I were designing Go2, I might also get rid of interfaces in favor of closures or explicit vtables (but that's a little puritanical and I might change my mind after programming in that style for a while). Still, I get things done faster in Go than I do in many of the languages that I've used professionally, like Python, JS, C, and C++.
People think Go is just like another language. I did when starting Go. And wanted to change many things in Go. After some months I do think Go is fine.
One thing I didn't use was embedded structs, I've used Interface more like in Java and Typescript. Now I use more embedded structs for what I would have used interfaces for and use interfaces more for embedding behaviour inside structs.
Go allows a wide range of complex metaprogramming through reflection, struct tags, ... to say that Go is void of that kind of garbage is lying.
Go also has a bunch of weird rules regarding type conversion and assertion, its type system isn't covariant... Go has its share of problems, so much that go maintainers themselves keep on introducing type unsafe API in their own std lib. Go has a type system problem, period.
Finally all platforms supported by Go aren't first class. Windows doesn't support Go plugins or Go shared libs AFAIK for instance.
Go's structs with associated methods and property/method promotion aren't that different from classic OOP. Too much is made of the differences, I think. You can recreate most basic OOP code in Go .... if you really must.
Honestly this is really compelling evidence that Pike doesn't know much about type theory. That isn't terribly surprising, and the other early collaborators on the language that I know of also came from more of a systems background. I think its entirely likely that Go's crippled type system is partly an accident, and not entirely a design choice. It would be helpful if - with the benefit of hindsight - they would admit it, rather than invent post-hoc justifications for the way things are.
If you are using GO like you use OO, you've missed the entire point.
https://twitter.com/rob_pike/status/942528032887029760
reply