Re: Implicit versus Explicit Dynamic Typing
Posted: Sep 19, 2005 3:26 PM
Thanks again for an interesting blog/article, Christopher. I'm glad to find there are other people who "rant" against the "freedom" of dynamic/weak typing, as well. I've never bought the "freedom to make type-related errors"-argument (ok, that may be a straw man, but that's much of my experience with dynamically/weakly typed languages). I've "ranted" about this in the context of PHP in a couple of letters to the Editor of an ACCU journal ("Overload"), where I also got a reply from a more pro-dynamical typing person.
As I said in my letters, this discussion is easily muddled by ill-defined terms, as there are several axes involved when it comes to type checking and type safety, such as:
- Statically/dynamically typed (whether the checking happens at compile-time or run-time).
- Declared/implicit typing (whether the type is explicitly declared, or inferred)
- Strong/weak type checking (how "eager" the conversions are)
"Type safety" is typically defined as guarantees against undefined behaviour (i.e. if you write the bit-pattern of an "int" into a "double", you most likely will _not_ get the equivalent floating-point value - you'll get undefined behaviour). I think it may also be argued that type safety is a measure of how well you may avoid type-related errors, as in silent cenversions hiding errors. A "prominent" example in PHP is that an empty string - "" - or even "null" may be silently converted to integer 0. I mean, come on... :) I've had no end of "fun" chasing down stupid bugs due to this "eager" conversion, that could have been trivially - and much earlier - been found had the rules of conversion been more strict.
Related problems comes from all type-checking being done at run-time, so if a branch of the code is executed only in rare circumstances, you may never know of a bug lurking there...
So far, I've talked about statical/dynamical checking, and eager/strict conversions. The last axis: implicit/explicit typing, is also interesting: Haskell is an example of a statically typed language, with optional type declaration. If a type is not declared, it's inferred. With quite strict conversion rules, even if you don't declare types, this may be a quite safe way of doing it. Type inference gives static checking, without having to declare the types.
In C++, types are mostly declared, but we also have some type inference in the form of function templates, and a couple of standards proposals ("auto" and "decltype") would allow type inference also in non-deduced contexts.
That said, there may be something said for being explicit in the code: for stating what is expected, and what is guaranteed. A declaration like "int f(int)" clearly states that the function takes an int, and returns an int. No ambiguity, there. Thus, inside the function, there's no need to explicitly check the type, so you won't have to write unit tests for something the compiler can very well check itself! Also, you're again guaranteed by the compiler that the type of the returned value is int, as well. So you may instead write tests for higher-level stuff.
I find it a bit of a paradox (and would _love_ to be enlightened on this...) that several proponents of agile development also advocate dynamical typing. Agile development is not at least about rapid feedback - catching errors as early as possible, and adjusting the design according to early feedback. Then, prey tell, why not get the compiler to help you, by giving you error reports even before you run your tests?! Some IDEs even highlight errors before the compiler is even run, for another thing.
Curious minds wants to know... :)