Other than that, generics have not really solved an actual problem for me in the real world. Nice to have, but too mush fuss about nothing relevant.
Other than that, generics have not really solved an actual problem for me in the real world. Nice to have, but too mush fuss about nothing relevant.
Second use I usually find is when I have some structs with some behavior and some associated but parameterizable helper. In my case, differential equations together with guess initializers for those differential equations. You can certainly do it without generics, but then the initial guess can be the wrong shape if you copy paste and don't change the bits accordingly. The differential equation solver can then take equations that are parameterized by a solution type (varying in dimension, discretisation and variables) together with an initializer that produces an initial guess of that shape.
Finally, when your language can do a bit of introspection on the type or the type may have static methods or you have type classes, you can use the generic to control the output.
Basically, they are useful (like the article implies) when you want to statically enforce constraints. Some people prefer implicitly enforcing the constraint (if the code works the constraint is satisfied) or with tests (if the tests pass the constraint is satisfied). Other people prefer to have the constraints impossible to not satisfy.
That's my experience as well in C# - most of other usages of generics are painful to maintain in the long run. I've had most problems with code that joins generics with inheritance.
They are far closer to Rust in some areas (definitely not in type inference sadly, but F# is a different story) than it seems.
Of course if one declares that they are an expert in a dozen of languages, most of which have poorly expressive type systems, the final product will end up not taking advantage of having proper generics.