All programming languages have a type system. Typically, we classify
these type systems as either static or dynamic. A shift that’s taking
place is to include type inference engines within a programming
language that allows the developer to realize the safety benefits of
static typing and the flexibility and expressiveness benefits of
dynamic typing. I talked briefly about these ideas in The New Era of Programming Languages.

For many though, the whole type system issue comes down to
compilation. Statically typed languages require type information
because the compiler needs to verify that the type is not used
incorrectly throughout the program. Dynamically typed languages
typically don’t have a compiler, so the type verification is left to
run-time.

So in general, we typically say that statically typed languages are
safer because the compiler catches certain types of errors at run-time,
but dynamically typed languages are more flexible and expressive
because we don’t need a bunch of language constructs to get us past the
compilation step. A good example of this is an interface in Java. A
class needs to implement an interface simply to get past the compiler.
At runtime, that interface provides no value. Dynamic languages
typically rely on duck typing instead of inheritance. Other interesting aspects of a language’s type system include covariance and contravariance,
which are related to how types are ordered within a class hierarchy,
and impact how the language deals with return types and method
parameters.

But there is another dimension to a language’s type system that
often goes unnoticed. A language is either strongly or weakly typed.
For years, we’ve recognized Java as a statically typed language, while
Ruby’s type system is dynamic. Because Java is statically typed, it’s
natural to assume that is also has a strong type system, and since Ruby
is dynamically typed, it’s easy to assume it has a weak type system.
Not quite so true, however. Time for an example.

Let’s take the same simple program, written in both Java and Ruby.
The code in Figure 1 is Java code that attempts to add a String and an
int.

In some cases, Ruby is actually more strongly typed than Java, but
the dynamic type system of Ruby delays discovery of the problem until
runtime. Java, on the other hand, is a statically typed language that
uses implicit type conversion in special situations. This implicit type
conversion results in a weak type system, meaning the program can
suffer from undesirable side affects if the implicit conversion is not
the desired conversion, yet no runtime error results.

The point here is that while Java is statically typed and Ruby is
dynamically typed, we cannot categorically say that Java is safer and
Ruby is less safe. The runtime type system has the final say in making
that decision.