This is not the first time I argue this case, but I would go a step further and say that not having generics is feature of Go.
There are plenty of languages out there with Generics. I use several of them. I use Go when that suits me, and it's typically for cases where high readability trumps doing a lot of magic with generics. I think only once or twice have I thought to myself, "this would have been better with Generics".
Generics aren't magic, and they aren't Turing complete, like C++ templates. They're just a way to avoid copy-pasting code.
Having `Set<Foo>` and `Set<Bar>` is far more readable than `class FooSet` and `class BarSet`, where the code is exactly the same aside from a search-and-replace.
You also run into issues where someone finds a bug in `FooSet`, but doesn't know `BarSet` exists, and forgets to patch both. Now, you have two divergent copy-paste classes.
Generics solve a bunch of real-world problems, in a very simple manner.
Sorry, when I said new data structures, I meant containers like maps and list, which I very rarely get to create day to day.
I can see it for your transformations, but I have seldom seen cases where generics would really help (usually we're talking about comparing complex structure types that will need custom code anyway).
"Theorems for free"! By which I mean, when I'm coding something and it could be universally quantified on the type, then it's better to do so. That way, it's impossible to phrase certain errors. For example, a function `Set<a> -> Set<a>` must produce a subset of the input set; that's guaranteed by the types. I can't accidentally include the value 0 in my set, because 0 isn't of that generic type. The generic forces you to think in terms of the structure you're manipulating, rather than in terms of its contents.
You can't use interfaces to prevent inserting values of the wrong types into a set. When you view the purpose of types as preventing bugs, that seems like a giant missing feature.
“Can you give a real world example that couldn't be solved with interfaces?”
Of course not. Go is Turing complete, and generics do not make it Turing-completer (whatever that may mean)
The question isn’t about what can or cannot be done, but about expressiveness, ease of understanding for humans versus language size (even if you have plenty of disk and RAM, That correlates with buggyness of the compiler) and compilation speed.
I think you're looking at it wrong. You can absolutely solve it with interfaces, the problem is those interface methods are identical, so it's duplicative.
> I think you're looking at it wrong. You can absolutely solve it with interfaces
There are lots of generics use case you either can't solve at all with interfaces, or you have to contort every which way and usually lose something in the process (type-safety, performances, readability, …).
> Can you give a real world example that couldn't be solved with interfaces?
There are none, you can always work around them, with the only downside is that you'll move some potential compile-time errors to runtime errors.
But that's the wrong conversation to be having; we could also say "why do we need floats? Everything can be solved with ints too", which is true, but also a lot of work and a poor trade-off. Similar arguments exist for many language features.
So it's a question of trade-offs: how much time will this save people? Will it reduce faults? And what are the costs of adding this? And how do they balance?
The introduction of generics would not change your workflow though. You could still happily "not use it" and keep matters readable. Others who wanted it, would use it.
That ship already sailed with widespread misuse of interfaces. Consider:
package foo
type T interface { func Bar() }
func New() T {
return &someotherpackage.ImplPickedAtRuntime{...}
}
Now whenever you see:
x := foo.New()
x.Bar()
You have no idea where to read the code for Bar. For maximum fun, ImplPickedAtRuntime should then contain members that were allocated in the same way. What should be a simple M-. then eats up your entire afternoon.
If others people code uses it, then those other people deemed it useful.
So the argument for not having them now becames either:
(a) they rather not have it available, because you personally don't find it useful
(b) those using generic don't know what they're doing, and only people not using generic are smart, so it's better to not have them to prevent the clueless from being able to use them
Like I said, I use (and like) several languages that have Generics, and when I need to do something where it makes sense, I can reach for those. For me there was an advantage in having a language where it wasn't an option.
Your (b) scenario is quite a strawman. I have seen plenty of good code using Generics, but sure, there is subset of code written using Generics that is not good, and I think it becomes easier to obfuscate code and make it hard to read if you have Generics, that might just by my bias, and I think I'm tainted from C++ and hopefully it will never become as bad as what you can encounter there.
I'm not trying to make out that Generics have no place in Computer Science. I was trying to make the case for it being nice that there was a language that didn't have it, and was building on the grandparent saying that he didn't miss it that often, which mirrors my experience with Go.
This is a silly strawman. Developers often write hard to read code, and even if generics are useful to the writer, doesn't mean they are useful to the reader. Many developers do not consider the reader, or if they do, not very in-depth. You can also make the argument that generic code is uniformly harder to read than specific code.
There are plenty of languages out there with Generics. I use several of them. I use Go when that suits me, and it's typically for cases where high readability trumps doing a lot of magic with generics. I think only once or twice have I thought to myself, "this would have been better with Generics".