Fabian, first let me confess that I'm an outlier in that most of my OO experience is in dynamically typed languages, and that in my code, I don't get run-time type errors. Because my experience is that dynamic typing is perfectly safe, I find myself resenting having to enter type annotations when I work in statically typed languages. While I appreciate the fact that static typing means that I don't have to write some tests, I hate having to add this extra code.
Having said that, I realize that many folks have had different experiences with dynamic typing. I write trustworthy code where objects behave like you'd expect. This means that I can trust that any object with which I'm interacting just works. This, in turn, means that I don't have to check if objects behave the right way. Sadly, I've seen many OO applications where these things were not true. Folks fall into the trap of writing code that's not trustworthy. Because they can't trust message sends to return objects that behave correctly, they have to check the type of the return of messages sends. This leads to a descending spiral of manually adding type checking, and code which ultimately breaks in confusing and painful ways.
Here's the deal. The power of dynamically typed OO languages is attained only when you write trustworthy objects that use duck-typing and polymorphism, and then trust them to behave correctly. If for some reason (inclination or background) you can't prevent the creation of untrustworthy objects, it's probably better to use static typing.
These styles of programming are different, and combining them leads to the worst of both worlds.
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.