Extra steps that guarantee you don’t accidentally treat an integer as if it were a string or an array and get a runtime exception.
With generics, the compiler can prove that the thing you’re passing to that function is actually something the function can use.
Really what you’re doing if you’re honest, is doing the compiler’s work: hmm inside this function I access this field on this parameter. Can I pass an argument of such and such type here? Lemme check if it has that field. Forgot to check? Or were mistaken? Runtime error! If you’re lucky, you caught it before production.
Not to mention that types communicate intent. It’s no fun trying to figure out how to use a library that has bad/missing documentation. But it’s a hell of a lot easier if you don’t need to guess what type of arguments its functions can handle.
This works as a general guideline, but sometimes you aren’t able to write the code in a way that truly self-documents.
If you come back to a function after a month and need half an hour to understand it, you should probably add some comments explaining what was done and why it was done that way (in addition to considering if you should perhaps rewrite it entirely).
If your code is going to be used by third parties, you almost always need more documentation than the raw code.
Yes documentation can become obsolete. So constrain its use to cases where it actually adds clarity and commit to keeping it up to date with the evolving code.