In 1974, Liskov and Zilles defined a strongly-typed language as one in which “whenever an object is passed from a calling function to a called function, its type must be compatible with the type declared in the called function.” Strong type checking, without doubt, decreases the amount of type errors, which leads to higher quality. However, the question is: do we really need types in order to strongly enforce typing?
For example, this is a place where we expect an instance of Java interface Book
to arrive:
void print(Book b) {
System.out.printf(
"The ISBN is: %s%n", b.isbn()
);
}
The type Book
may look like this:
interface Book {
String isbn();
}
If an object that doesn’t implement
the interface Book
is passed to the method print()
, the compiler will complain with the “type mismatch” error. It will be hard for a programmer to make a mistake and pass an object of type, say, Car
to the method print()
. However, it will still be possible, via dynamic type casting:
Car car = new Car("Mercedes-Benz G63");
print(Book.class.cast(car)); // Here!
This code will compile without issues, but at runtime the ClassCastException
will be thrown, since it won’t be possible to cast Car
to Book
.
The beauty of strong typing is that it prevents errors. However, it increases the complexity of code: you need to create types first, you need to declare them in all your functions, you need type casting, which is hard to debug, and so on. Weak typing proponents complain about this a lot and create languages like Ruby, which don’t have types at all, for example:
def print(b)
puts(format("This is ISBN: %s", b.isbn))
end
Here, the function print()
doesn’t expect b
to be of any particular type. Whatever comes in—is fine. Later, when it’s time to call .isbn
the runtime checks whether the incoming b
has such a method. If it does, everything works just fine, if it doesn’t, a runtime error NoMethodError
is raised.
So far so good.
However, here is the idea: what if we combine the simplicity and brevity of dynamic typing with the safety of strong typing by getting rid of types all together and letting the compiler infer type information from the code that works with the objects? Here is our code again:
void print(Book b) {
System.out.printf(
"The ISBN is: %s%n", b.isbn()
);
}
Think about this: at compile time it’s already obvious that b
must have at least one method isbn()
. No need to force programmers to define the type Book
explicitly and mention in the signature of the method print()
that only books are welcome: this knowledge can easily be inferred from the body of the method print()
! The compiler may look at all statements in the method print()
and clearly understand what exactly will be done with the object b
. This information should be enough to visualize the “type” of the incoming object. No need to ask the programmer to do this explicitly and spend another five lines of code in a new file to declare the type Book
. The compiler together with the IDE can do this job for us.
Of course, to make this work we must prohibit type casting of any kind, which is not possible in Java, C++, C# and other pseudo-object-oriented languages. But it is possible in EO!
WDYT?