The hypothetical strength of a type
In a previous post, I alluded to the idea that “weakly typed” and “strongly typed” have no clear definitions and they aren’t useful concepts. Generally, when it’s said “Language X is weakly typed”, one is led to think that “weakly typed” is a characteristic of language “X”. It may also lead one to think that a type or type system can be “weak” somehow.
In this post, I argue that so called “strong” and “weak” types are not a property of the type system — much less of a programming language — and that this strength notion is a mischaracterization of issues which arise whenever operators or functions are overloaded and the overloaded behaviors and the type combinations in the signatures become complex.
The case of Javascript
Consider the +
operator in Javascript. With it, we can perform computations such as:
As a language designer, at first sight, overloading +
seems like a great convenience which spares the programmer’s code from the noise of casts. But in practice, that versatility comes with a price.
In the code above, the first 2 lines are usually considered safe and predictable (i.e., int+int
, float+int
) but the remaining examples (3–5) are, in increasing order, considered a source of problems. Overloading arithmetic operators to that extent allows for arithmetic expressions resulting in “weird values” without raising errors. Consider the following Javascript statement:
execute_sql("SELECT * from table where col=" + (a + b) * 1.5)
When a
is the string "10"
and b
is the number 2
, it evaluates to:
execute_sql("SELECT * from table where col=153")
That is, instead of 18
(if a
was the number 10
) we get 153
as result. Presumably, because these operations don’t raise a type error when used with such diverse types but, instead, return a “normal” value, programmers seem to think the type system has been relaxed or weakened. But the behavior is simply a particularity of the operators themselves. These are operators that have been overloaded to a point that reasoning about them is not easy.
In fact, we can define that same Javascript +
operator in a language like Haskell:
In this Haskell example, we created and overloaded the operator |+|
to behave roughly the same as Javascript’s +
(the main function executes the same expressions and prints the same results as our weakly.js Javascript snippet above). Now, did this code turned Haskell into a weakly typed language? Or, perhaps, did it weakened it’s type system? The answer to both questions, naturally, is no.
By inspecting the code, we should conclude that assumptions about implicit casts are not needed as explanation for the perceived weakening of the typing rules. Rather, the diversity of types clearly defined in the signatures of the |+|
operation is sufficient. Then, we can reasonably infer Javascript’s +
operator could be modeled similarly as an overloaded function and conclude it‘s type can be precisely defined in a sound type system.
Furthermore, even though Haskell provides a static type checker, it’s unclear if there would be a guarantee that all bugs that occur in Javascript due to these overloadings would be caught by the checker. Consider the snippet below as a statically typed code:
execute_sql("SELECT * from table where col=" + (a + b))
For an operator +
overloaded to accept a mix of numbers and strings, the code above type-checks whether the variables a
and b
are numbers or strings. Likely, the type checker could only identify a problem when, for example, a
is defined to be of a number type and the assignment of a string to it would fail.
Therefore, we can only conclude that “weakly typed” can’t be a characteristic of the language, nor of the type system. It it but a misnomer that merely indicates the presence of functions or operators with a complex/unintuitive signature/behavior where one is easily led to wrong assumptions about them [and there’s no static type checker to help]. Q.E.D.