It's very relevant. In fact I would argue that type systems only address the simplest possible errors and do absolutely nothing about the most complex, time-consuming errors such as those related to unpredictable state mutations caused by multiple events being processed in parallel or having different parts of the code operate on the same instances.
In fact, I would argue that static typing encourages developers to define more complex function interfaces which creates stronger coupling between components in the code and this leads to instances being passed around/shared between more different files and this is more likely to lead to unpredictable mutations of those instances' state. It makes it easier for developers to neglect good separation of concerns.
Dynamic languages make it more difficult to keep track of complex instances between different functions and files so they encourage developers to pass more primitive 'pass by value' arguments; this results in looser coupling between the components.
Dynamic languages encourage more modular, more interchangeable code. This is why the most popular package managers of all time are based on dynamic languages like JavaScript (npm) or Ruby (RubyGems) and not on statically typed languages; it's not a coincidence.
statically typed languages with dependent types solve this problem of “static types not catching off-by-ones”, although I question the premise of these being the most common software bugs. Perhaps in a CS class these are the most prevalent?
Furthermore,
> Dynamic languages encourage more modular, more interchangeable code.
Have you ever used an ML or another typed language with an actual module system? It makes these dynamic languages look duct-taped in comparison.
In fact, I would argue that static typing encourages developers to define more complex function interfaces which creates stronger coupling between components in the code and this leads to instances being passed around/shared between more different files and this is more likely to lead to unpredictable mutations of those instances' state. It makes it easier for developers to neglect good separation of concerns.
Dynamic languages make it more difficult to keep track of complex instances between different functions and files so they encourage developers to pass more primitive 'pass by value' arguments; this results in looser coupling between the components.
Dynamic languages encourage more modular, more interchangeable code. This is why the most popular package managers of all time are based on dynamic languages like JavaScript (npm) or Ruby (RubyGems) and not on statically typed languages; it's not a coincidence.