> Such holes include for example the ability to use Object and then downcast in Java and have the implicit contract that the people using them know what they are doing,
It's worth noting that this is still not quite the same as the leeway that most dynamic languages allow you, because, while you can downcast, all such downcasts are checked. You can't just say that Foo is a Bar, and proceed to treat it as a Bar, in Java and similar languages. You can assert (via a typecast) that it ought to be a Bar - but if it's not, you just get an exception or some other indication of failure.
As a result, it's much, much more difficult to hammer square pegs into round holes in those languages. As it should be.
It's worth noting that this is still not quite the same as the leeway that most dynamic languages allow you, because, while you can downcast, all such downcasts are checked. You can't just say that Foo is a Bar, and proceed to treat it as a Bar, in Java and similar languages. You can assert (via a typecast) that it ought to be a Bar - but if it's not, you just get an exception or some other indication of failure.
As a result, it's much, much more difficult to hammer square pegs into round holes in those languages. As it should be.