BUT, I need generics all the time indirectly. I've worked in lots of languages over the decades, and I highly value languages with mature/debugged/optimized standard libraries of algorithms and data types (esp. "containers").
Go has an impoverished subset "built-in", and that's all it offers.
One of the best things about Go is the high quality of its standard libraries--where it has standard libraries--so there is a gaping hole where the container and algo libraries ought to be. Experts in these algorithms could take advantage of Go's concurrency for example to write library algorithms that provide a combination of performance and safety that I couldn't create quickly if at all. They could, that is, if they had generics in the language, but they don't, so I'm on my own (for now).
When people (repeatedly) claim that Go doesn't really need generics because they (the claimants) hardly ever need generics, I have to wonder whether their knowledge of DS and algos is especially high or especially low: that they could whip up a debugged and optimized algo as easily as calling it from a library or whether they aren't even aware of the DS/algo that they really ought to be using.
Lots of people find the things you're concerned about missing to not really be the end of the world.
Or you might hate it, and that's also okay.
But those are the only container types with built-in support like that. (Channels can similarly be of any type)
If I remember correctly (haven't used it in a year) Go cheats a bit, and it has few functions in standard library that do have generics (like make), it just doesn't provide this functionality to the developer.
That’s not really true, since built-in containers are special sui generis generics in Go, whereas in an untyped python they get by being untyped, and in python’s statically-checked type system (as implemented in pyright, mypy, etc.) they use general-purpose generics.
At any rate: the person asking the question is wondering how you manage to have performant containers with reasonable interfaces in a language without generics. That's a good question! If you've worked a lot in C, you might be imagining a horrible mess of void-stars or something. But no, the ergonomics are basically those of Python, with extra typing.
I really don't understand how the python comparison makes sense. Since those particular containers are special cased, the ergonomics are also the same as java (and I'd argue more like java than python). Other than ownership, I don't think go's maps are any more python like than C++s or Rusts either.
> reasonable interfaces in a language without generics
and with static typing. Python doesn't fall into that category. It either doesn't have static types, or does have generics. The answer (as others have mentioned) is that go does support generics for a few particular container types.
I’m not making a complaint, I’m pointing out a fact without a value judgement.
> At any rate: the person asking the question is wondering how you manage to have performant containers with reasonable interfaces in a language without generics.
Uh, I don’t see either “performant” or “with reasonable interfaces” there, the question is: “How do container types, like arrays or hashmaps work without generics? Do you basically have to declare and implement types/methods for each different contained type?”
The answer is, for built-in containers, “no, because they use special-purpose generics”. For custom containers, its basically “yes”, but you probably only want a single contained type with an appropriate interface anyway. In neither case is “basically the same as Python” particularly accurate, though I suppose the former case is similar to typed python using generics in the same way as any language with generics would be, while the latter is loosely similar to bare Python or typed Python using protocols instead of generics. But only loosely.
Unless you want to implement utility helpers working on them then it’s yes again, because Go doesn’t have generic functions either, so while it does have a few builtin generic containers, you can’t operate genetically over them.
How do container types, like arrays or hashmaps work without generics? Do you basically have to declare and implement types/methods for each different contained type?