Monday, February 04, 2008

Static typing considered harmful

(Updated Info, 2014-10-29)
I still find almost no value in the static typing provided by Java. That said, I've done some ML lately and been very impressed with what types can provide. In addition, I've worked with some great programmers who do find value in Java's static typing.

If you take anything away from this blog entry, I would recommend this: No one can tell you which tools will make you the most effective, try them all and determine for yourself what helps you the most.

(Original Post, 2008-04-02)
Given a good test suite the return on investment simply does not justify the use of static typing.
In 5 years, we'll view compilation as the weakest form of unit testing. -- Stuart Halloway
Type verification provides very little confidence that an application works. The little confidence it does provide comes at the cost of being confined by the type system. Verifying types is better than testing nothing at all. But, only verifying types is insufficient for application development.

The obvious answer is to write more tests. As you write more tests, you can verify independent pieces of the application and integration of the different pieces of the application. Currently, you know that your code compiles; but that is to general to be considered sufficient for verifying system behavior. Specific tests can verify specific behavior. You may start out testing that 1 + 1 is a number, but eventually you will be better off testing that 1 + 1 is 2. The test that 1 + 1 is a number may have given you some confidence that your application was working, but once you add a test to verify that 1 + 1 is 2, the test that verifies that 1 + 1 is a number no longer provides you with any additional confidence. Since the test that verifies 1 + 1 is a number no longer provides any value, it can safely be removed.

21 comments:

  1. Anonymous3:03 PM

    Agreed, When I have mentioned developing in dynamically typed language such as Ruby to developers who use only statically typed languages a common response is that type safety is better, and therefore they are reluctant to consider a change.

    I feel that developers with TDD/Mock disiplin think more about the whole picture than Integers, Floats etc

    I will try and strengthen my argument to persuade them.

    ReplyDelete
  2. Anonymous7:53 PM

    I like both static and dynamic typing, but I highly doubt that static typing will ever go away or be considered "harmful."

    Dynamic typing is fine when I'm working on small scripts that I'm using alone - but I shudder to think what other random people will do with those functions/classes.

    With static typing, it's not so much that compiling tells me that a number is a number - it tells me that the programmer knows what he's supposed to be inputting. He took the time to look at the function definition - so hopefully he also read the comments to make sure that it is the right type of number.

    In other words, with static typing I know that the user has at least some idea what he's supposed input.

    ReplyDelete
  3. Anonymous12:38 AM

    Bruce Eckel (mostly) agrees with you: http://mindview.net/WebLog/log-0025

    ReplyDelete
  4. Anonymous2:35 AM

    You can write Unit test, but there is additional effort and code to maintain. Not necessarily more lines of unit test, the better quality. More code means more work to maintain. So only write efficient and good quality of unit test. But not for every single piece of code. Using static typing, for the rest, you can just rely on the compiler to the the verification automatically.

    Further more, static typing isn't only helpful that let compiler do some verification work automatically. It also help IDE to provide more help during your development such as Auto-completion, quick navigate between source code. Those IDE functions becomes more and more important in moderm development especially for large projects. But dynamic typing is missing that part.

    I personally like to use both static typing and dynamic typing depends on the real benifit.

    So do don't simply say static typing considered harmful without knowing really benefit of it.

    ReplyDelete
  5. Anonymous3:18 AM

    I think Dynamic typing deserves more credit than being used only for scripts.

    Why can't we use it for large projects too?

    I won't rely on the compiler, when I get no warnings that's great but the code I write is not trusted until tests are written for everything.

    PS Damage can also be done by random people using any language!

    ReplyDelete
  6. Anonymous7:23 AM

    Static typing sacrifices the future for the sake of a little convenience today.

    How many times have you run into a JAR (or other library in a statically-typed language) that you'd like to use, but where the @#$%^&* programmer mandates that you use his object hierarchy rather than yours? It doesn't accept POJOs. It doesn't accept POJOs-with-magic-interfaces. It only accepts subclasses of com.foobar.i.am.the.coding.Shiznit. Which means either you can't use it, or you have to tie all your code inextricably to this moron's classes, or you have to write a bridge and all the associated code to keep two copies of the object (one yours and one Shiznit) in sync. And heaven help you if you need two or more of these sorts of JARs.

    In a dynamically typed system, both the library author and the library user can dial in the desired level of sanity checking they want. The library author, for example, could test incoming objects from public interfaces to confirm they respond to certain desired methods. Or the author could write a facade that provides those checks, but could be bypassed if the library user determines it adds too much overhead. Either way, the library code itself -- other than perhaps the up-front sanity checking -- cares not a whit where the objects come from. It's as if it were all POJOs, all the time.

    ReplyDelete
  7. i've worked extensively with statically and dynamically typed languages. the benefit for me is not necessarily the confidence that an object implements a certain protocol, but the benefit that static typing gives in understandability.

    i.e. i can look at a method in isolation and know what is expected of an object passed into a method, and know what is expected of it downstream.

    This is particularly relevant on larger, modularised programs. one of the most unpleasant programming experiences I've had is being dropped into the middle of a reasonably large distributed smalltalk framework. none of the methods were documented, and it was very difficult to extract a mental model of some sort of type hierarchy.

    the idea has given me a thought -- perhaps the benefits of static typing could be realised in dynamically typed languages as a set of type assertions (almost tests) which are overlaid on type of the program -- i.e. like a set of test assertions. these assertions would be declarative and sit in a testing script, but would assert that a method (for instance) always expects that the first parameter conforms to the protocol Foo.

    The tests could be run over a specified body of code, using flow and whole program analysis.

    Andrew
    p.s. in all my time, i've yet to see someone show me a decent system that couldn't be modelled reasonably (and more understandably) with a static type system (obviously with type inference).

    ReplyDelete
  8. The only thing harmful I read from your post is your either-or mentality.

    ReplyDelete
  9. I mainly use static languages, but I really like Lisp and I think I'd like Smalltalk if I spent any real time in it (I prefer these over others because of their syntactic simplicity ). Static typing can prevent runtime errors, and the main barrier to using it to do so is that mainstream languages have awful implementations of it.

    Static typing might not be appropriate for all projects, or all parts of each project.. I think there's room for OOP in "the moving parts" of programs.

    I'd like to see/invent a language that allows you to gradually make code statically typed as you go.

    Static type systems don't have to be a pain in the backside, just because they are in each mainstream language that has them.

    ReplyDelete
  10. @Ricky

    re: adding static typing gradually.

    I believe Dylan allowed you to do this. This works well in languages which have multi-dispatch (a la CLOS).

    However, in single-dispatch (record type) models, this leads to a situation where you sometimes have the need for selective multi-dispatch. e.g. the crazy handling of notionally untyped variables in VB.Net http://www.infoq.com/news /2007/06/VB-Multiple-Dispatch

    (you'll have to take the space out of the url)

    Cheers,
    Andrew

    ReplyDelete
  11. Anonymous9:37 AM

    re: adding static typing gradually.

    Groowy and Haxe allow this.
    ActionScript from version 2 allows optional type specification, but in 2 this is checked only at compile time.

    ReplyDelete
  12. Anonymous10:26 AM

    What about creating a test that goes through your dynamically-typed code and checks for type safety in the same way that a compiler does? (So you don't have to write a unit test for every line of code.)

    ReplyDelete
  13. Anonymous11:05 AM

    Re:i.e. i can look at a method in isolation and know what is expected of an object passed into a method, and know what is expected of it downstream.

    When unit tests exist, it shows what is expected, what is isn't and how the implementation works.

    Automatic documentation if you like!

    When unit tests don't exist it's hard on all levels not just clarity..and it's up to us to write them.

    ReplyDelete
  14. Anonymous11:48 AM

    You are forgetting that there are static type systems well beyond the caliber of Java and the like. Coq (a theorem prover) is a statically typed system which takes advantage of the Curry-Howard Isomorphism to use types to actually prove properties. Coq is just a theorem prover, not a general programming language, but a lot of functional language research is heading in a similar direction (dependent types). With such a language, you don't even need unit tests. Anything you might want to test can be even more exhaustively proven by using the type system instead.

    ReplyDelete
  15. Sorry, people with that opinion just never encountered 5k classes projects.

    TDD won't help you a bit with maintaining legacy applications. The test just verify that nothing has broken (which doesn't mean you shouldn't do TDD, because doing TDD is a good thing).

    Peace
    -stephan

    ReplyDelete
  16. @james:
    When unit tests exist, it shows what is expected, what is isn't and how the implementation works.

    well, it can do to a certain level. but if the objects you return or accept also have substructure via other object, then the need to write tests becomes very, very painful indeed.

    you can think of static typing as this type of recursive test applied to give a level of sanity.

    Andrew

    ReplyDelete
  17. Anonymous4:21 PM

    When objects have substructure via other object mock objects are needed, TDD requires you to think of how to test it up front, using interfaces that can easy be utilised by mock objects etc (depending what lanuage and test framework used...)

    Old legacy code maintenance is more of a challenge, perhaps there's not a test framework along with other challenges making for a refactoring nightmare.

    It's easier to think how we shall do things in the future compared with what we have done in the past.

    It's been a good mix of thoughts.

    Take care.

    ReplyDelete
  18. Anyone who thinks static typing is analogous to unit tests must not be aware of modern tool support. In fact, I rarely if ever see compile time errors nowadays. My IDE catches them much sooner. In fact, thanks to static types, my IDE can help me write correct code in the first place. In addition, static types help me reliably navigate and refactor large code bases, and they serve to document my API, something you have to do in an unreliably ad hoc fashion in languages which don't have static types.

    ReplyDelete
  19. Nice one, Bob. I'd like to add that static types also allow us to analyze the algebraic properties of our code without actually having to run it. This lets us abstract over such algebras, giving rise to type functors and monads. This in turn lets us enforce the kinds of behaviour a program is allowed to exhibit; a stronger version of "design by contract" (as a simple example, Java methods must declare the kinds of exceptions they might throw).

    ReplyDelete
  20. Oh, and I almost forgot:

    Given a strict enough type system, unit tests can be generated automatically.

    So... writing unit tests is actually a complete waste of time, since the machine can write them for you.

    ReplyDelete
  21. Anonymous12:54 AM

    Using the word "verify" both for what unit testing does and what static type checking does is a little misleading. When the static type checker says "ok", I'm absolutely sure that my program will never, at any point, try to access a non-existent field (for example). The type checker has rigorously proved the absence of a certain class of errors.

    When my test suite says "ok", I just know that, along whatever execution states happened to be exercised, nothing crashed. It's not computationally feasible to test every execution state. What some people call "100% code coverage" is not the same as 100% execution state coverage.

    It's a trade-off. A type checker can only handle relatively simple properties. A unit test, being unconstrained code, can test whatever it wants, but it can't prove anything in general.

    Also, people are still working on making type systems better. For example, the Sing# language from Microsoft Research has syntax to describe the states in a communication protocol. The type checker can then ensure that your program will never send or expect to receive the wrong type of message for the current communication state (ex: if you haven't sent your login credentials yet, you aren't allowed to send a resource request). Of course, you still have to make sure you're not putting garbage in the message body, which is something you would need to write tests for. But I think it's still valuable to have the absolute guarantee that there is no corner case where your program logic gets confused and ends up sending the wrong message type.

    BTW, if your experience with static typing comes from Java, C#, or C++, you should know that their type systems are a little ways behind what's considered good practice these days. Look at a functional language like Haskell or an object-functional hybrid like Scala. In those languages, the static type system imposes a lower cost on the programmer, yielding a better cost-benefit ratio.

    ReplyDelete

Note: Only a member of this blog may post a comment.