Some reasons in favor of explicit typing (I am not talking about static vs dynamic here, just about the possibility annotate the expected type of a certain thing):
1. It can serve as code documentation. In some cases, with some kinds of programmers, the only documentation that you have is code itself (although this would require compulsory explicit typing which doesn’t happen always – groovy, caml and scala are examples of exceptions – in many cases saying the type is optional)
2. It helps IDEs help you. There is some discussion that IDEs for non-explicit (actually dynamic) languages can be as helpful as static languages. Well, if the information is there, then surely the IDE case use it and help you.
3. Bugs. Maybe your function is working and should not be working. Maybe the object, which should never be passed to that function is responding just because there is a signature that matches. I find this pattern somewhat common: a) There is a function parameter (without the explicit type) on a buggy function call. b) I put the type in on the called function. c) It immediately becomes clear that somewhere I am passing something that shouldn’t be going in in that form, a pseudo-code example:
myFunction(a, b) {
String x = a + b
print x.toUpperCase()
a should be a String (+ is a concatenation), but for some reason myFunction gets called with a as an integer and kaboom (+ is interpreted as addition).
This can be quite insidious with type inference (CAML for sure, probably Scala also) where you can get a bug on a chain of say, myFunction3 calling myFunction2 where the bug is somewhere else (say another myFunction1 which also calls myFunction2): When the compiler reads myFunction1 it does a wrong type inference about myFunction2. Afterwards, when the compiler passes on myFunction3 it complains, but the bug was caused elsewhere (so the information from the compiler is useless). If you put the type on myFunction2, the compiler will whine on the correct place (on the myFunction1 call). These bugs can be a pain to detect because sometimes the chains can be long. I had the “pleasure” of spending countless nights with caml tracking these bugs. 15 years ago, but I still remember.
Anyway, non-compulsory explicit typing (a la Groovy, Scala, CAML) is a good compromise (use it if you like it). In fact, in some cases it is good to be lazy anyways
PS – As far as I remember in Groovy and Scala there are cases where explict typing is compulsory anyways (correct me if I am wrong). I would suppose that comes as a need as those languages and JVM and Java friendly by design and the compiled code will require that info.
James Iry says:
When a language has inferred static types (Scala, Haskell, ML, F#, etc), an IDE has exactly as much information as when you explicitly annotate types. Basically, inferred static typing can be thought of as the tool inserting the type annotations that you leave out. So scratch the IDE concern off your list for those languages. Groovy is very different, so this reasoning doesn’t apply there.
Usually static type inference does not cause an invalid program to type check. But what it can do is give a static type error that’s pretty far removed from the “real” source of the problem as seen by the programmer. Scala requires type annotations on arguments to functions which is a bummer but on the plus side you don’t tend to have that kind of chained inference problems. In languages with fuller type inference (Haskell, ML, F#) it’s common practice to annotate types on many or most top level definitions just to prevent that kind of problem.
Scala’s compulsory type annotations on function arguments has to do with the limitations on currently known inference algorithms and how they relate to subtyping and overloading. F# also has some, though far fewer, spots where it needs explicit type annotations.
December 31, 2008, 16:27