If you really need generic structures you can use the interface type but generally there's a simpler solution that doesn't require generics.
If you really need generic structures you can use the interface type but generally there's a simpler solution that doesn't require generics.
Having said that, I honestly don’t know if generics are a net positive or not. What I can say is that go is one of the few languages where I can jump into an arbitrary go code base and make sense of it relatively easily. Risking that is a scary proposition for me.
Generic data structures are provided in many programming languages and there are many people that are very experienced in writing some of these, so being able to reuse, it's precious.
In general the lack of generic price surfaces when you write libraries, not applicative code. But libraries are a big portion of a codebase.
Still in my short Go career, I worked on at least 4 libraries, one of those needed generics to gain a huge performance boost, the other worked around the lack of generics, but I still wish it had it (a special kind of logger). In applicative code, the main issue with lacking of generics is the lack of generic slices functions (map/select). Initially I thought it would be fine, but then I wrote a piece of code that was visibly involved in copying data from one slice to another with some changes and that "shadowed" the "central" part of the code behind a bunch of loop codes. In those cases, to improve the ability to easily scan through the code, I wish I had some generic slice function to deal with it. I appreciate doing loops, but sometimes they are verbose enough to hide the interesting part of a piece of code. This is especially visible in applicative code where usually performance is not as important as much as the business logic.
I'm very intrigued by the no-generics idea, so I'm prodding at what might've made it workable enough that this reversal wouldn't be necessary :)
Well in Go the assumption is that you jump to interface{} (equivalent to Object in Java or void* in C) when you start having these kind of problems, but there is a performance penalty in doing that, which shouldn't be there if generics are present (and makes the code DRAMMATICALLY worse with all the casting)
> Having said that, I honestly don’t know if generics are a net positive or not. What I can say is that go is one of the few languages where I can jump into an arbitrary go code base and make sense of it relatively easily. Risking that is a scary proposition for me.
I don't see how type params would make this harder, I daresay I can think of a lot of instances it's much easier. The caveat is that you simply don't understand them, in which case it's a good thing to learn as many languages do have them.
In any case all these arguments are well trodden so I'm probably wasting my breath re-hashing here.
That said I don't think there's much "hope", from the looks of things it is coming to Go.
I understand generics well, I just find code bases that use a lot of abstractions harder to read than Go.
That's pretty laughable considering the language designers included type-parameterized collections in the language. Apparently they recognized the need for them; they just didn't think you were smart enough to make your own. After all, Go was explicitly designed for programmers who are, in the words of its creator, "not capable of understanding a brilliant language".
For merge mortals it is a tool hard not to misuse full of hidden traps and debugging of code written even by the very best developers (surprise - it has bugs too) is a challenge.
Go just did a step towards C++, even if a tiny one.
I jest, but I also don't. All the best developers I know strongly prefer footgun-free libraries and primitives. The advantage is that you don't _need_ to spend brain cycles checking and double checking that it was written correctly, and when you want to make changes you don't need unwind an elaborate abstraction to stretch it further.
In martial arts (I'm a second degree black belt), the third move you learn is the round house kick (turned leg kick - the first two moves are the punch and the straight leg kick). At the olympic level, 70% of all points are scored using a roundhouse kick.
The other funny thing about the roundhouse kick is how much you can learn from watching someone do a single one. You can tell the difference between someone with 2 years of experience and 3 years of experience, and you can _also_ tell the difference between someone with 15 years of experience and 20 years of experience.
The point of this story being that masters are masters not because they can do elaborate techniques, but because their command over the simplest techniques is superlative.
I've found in life that this applies to pretty much everything. Martial arts, programming, painting, cooking, and effectively any task that definitively has some people who are better than others.
But I know what you mean. I've worked on Scala code for years and seen less mature developers over-engineer things and get way too clever with the type system. Scala is a really practical and powerful industrial language that requires some maturity to use the abstractions sparingly. It's only good for the top 5% of developers.
However, Go doesn't have such a powerful type system. It looks like the Go designers implemented relatively simple generics. You have to draw the line somewhere. If simple Go generics are too confusing and complicated then that developer should probably find another job, as generics are a basic concept in programming. The Go designers are pragmatic people, and they've decided that relatively simple generics will make things easier in mainstream commercial codebases.
But some people have a tendency to play code golf with their codebases.
I have, for example, encountered a "generic data structure" that looked like a normal linked list on the surface. BUT, it actually sorted the largest three items in the first 3 cells and the average in the 4th.
That was multiple days of work wasted because someone decided to be cute with their data structures. And that wasn't even the only one of such "generic" monstrosities in the code.
It's true that applicative code shouldn't need generics in probably more than 90% of the times, however the lack of it affects library authors quite heavily
I don’t agree with you, but I could be wrong. There are plenty of languages that are aligned with your point of view. I like go because it was going a different direction, and I hope that doesn’t change. You can use Haskell, scala, typescript, etc to get what you are looking for.
Even for your own single-person projects - if you get fancy with the code, 6 months later you find it's a lot harder to get back into and mess around with than if you had written the code as though you were presenting it to a beginner.
In Go prior to generics, interface{} is an escape hatch less frequently needed but not necessarily much safer than void*. Post generics, interface{} is suddenly more useful and will be aliased by ‘any’.
The way the std lib heap works in Go, an implementation doesn’t have to mention interface{}. Using the Go std lib solution is about satisfying a few interfaces, defining some methods for sorting and swapping over the element type. The use of interface{} is internal.
Go’s generics solution is going to have type constraints, which I think will be very familiar to some and probably new to others … So, the Go generics PQ should still require some constraints on elements, not ’any’thing will work. I’ve really enjoyed constraints in languages and it’s not quite natural in C++/Java, but Go’s interfaces already do some ‘constraint’ work conceptually and can be used as constraints in Go’s generics syntax. I’m interested to see how this plays out.
You can cast void* to anything you want. With interface{} you get a type check, either through an assertion or a panic. That is a big difference in safety.
I was thinking more about silence where someone expected a greater degree of compile-time type safety than they really had, or relatedly e.g. the subtleties in JSON encoding / decoding where there is silent data corruption that could fall through the cracks - mostly I feel like I avoid these things by not using interface{}; I certainly did not grasp that without some experience with the language.
Sometimes - especially in other languages - you see a piece of "elegant" code that does something complex in line 3 lines, and you think "hmm, this is a puzzle, and I'm going to be staring at it for 20 minutes before I'm convinced that its 100% correct."
We actively tell our engineers not to be clever. Write boring code that is obviously correct, and don't worry if your boring code is 25 lines when the elegant code is 8. It takes you longer to write the elegant code, and it takes the reviewer longer to read it, and often times (though not always ) it's also more difficult to test.
I love Go because of how boring and consistent and easy to read it is. The language and the task of "programming" melt away and instead you get to focus on solving problems.
Using generics isn't 'clever'. It's like saying a loop is clever. It's abstraction, the opposite of clever.
Doesn't mean many of us want to keep living on that world.
I advise reading books like "From Mathematics to Generic Programming"