This is a mobile version, full one is here.
Yegor Bugayenko
10 November 2020
Strong Typing without Types
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?