
Dynamic typing and anti-lock brakes - johndcook
http://www.johndcook.com/blog/2010/06/09/dynamic-typing-and-risk-homeostasis/
======
jrockway
Yes, this is true, the dynamic language communities have compensated for the
lack of a type system with explicit type checks (or type constraints) and lots
of testing. But it's still nice to have a real type system (and I don't mean C
or C++ or Java; those languages also have no type system). When I compile a
Haskell project successfully, I have a reasonable belief that it's going to
run to completion and at least produce some sort of result. The same is not
true of Perl, even with lots of tests, my programs almost always die in the
middle (during development) where a runtime type check or assertion fails.

The reality of programming is that all functions and variables have types. If
you add 42 to "hello world", you get garbage. In dynamically typed languages,
you keep the types in your mind -- you know that the variable you are adding
42 is a number. In statically typed languages, you tell the compiler. The
second way lets the computer do some of the work for you (ensuring that if you
use the variable like a string, your program won't compile), the first way
requires you to do everything. If you aren't careful, you get the wrong answer
or a runtime error.

I think dynamic typing was a nice way for the programming language community
to realize that C's type system sucked, but it isn't the ultimate answer, it's
just a stopgap. It's also good that people realized they needed to test their
code automatically; but that works _even better_ with statically-typed
languages.

Anyway, I am not going to give up Perl anytime soon, but I secretly wish it
wasn't dynamically-typed.

~~~
jcsiracusa
Is running to completion and producing an incorrect result really preferable
to dying in the middle of execution due to a runtime check or assertion?
Either your program works or it doesn't.

~~~
jrockway
Yes.

~~~
gnaritas
No. Failure is failure.

~~~
paulbaumgart
With dynamically typed languages and implicit variable declarations, I find
the most common runtime errors are, in descending order of frequency:

    
    
      * Something returned null when I assumed it would return a value/object.
      * I used the wrong variable.
      * I made a typo in an assignment that implicitly created an unused variable
        (this is easy to catch with static analysis even in dynamically typed
        languages, admittedly).
    

The first one is by far the most common.

I'm not particularly experienced with Haskell, but my understanding is that
the static typing will usually catch the second one and that more advanced
static analysis (more advanced than type checking) can easily catch the third
one.

Most important, though, is the case of the first and most common error. Here,
the language will very explicitly require you to handle the case that
"Nothing" will potentially be returned.

So, most of the sorts of errors that would have caused failed execution in a
dynamically typed language will be caught at compile time. This means that
when the program runs, it will usually be closer to being correct than it
would be if it were written in a dynamically typed language and failed in the
middle of execution.

~~~
jrockway
_Most important, though, is the case of the first and most common error. Here,
the language will very explicitly require you to handle the case that
"Nothing" will potentially be returned._

Well, actually no. Consider:

    
    
        divide :: Int -> Int -> Maybe Int
        divide x 0 = Nothing
        divide x y = Just $ x / y
    
        printResult :: Maybe Int -> IO ()
        printResult (Just x) = print x
    

Now, run:

    
    
        main = do
          putStr "Type a number: "
          x <- readLn
          divide 42 x >>= printResult
    

This will still die if you type 0, because there is no pattern to match the
Nothing case. Sure, you can run Catch to see that you made a mistake, but the
compiler doesn't care. (At least you can run Catch to determine that you
messed up, though. If you are using Java or Ruby or something, you are just
hosed.)

Anyway, my usual error is not null or using the wrong variable or typoing
something. It's usually failing type checks because I forgot a coercion, or
just plain wrong code. Exceptions prevent null returns, and I am lucky with
respect to the other two.

~~~
paulbaumgart
Interesting. I assumed Haskell would at least warn you. But it's probably only
a matter of time before Catch is built in to the compiler, at least as an
option.

~~~
kragen
OCaml does warn you:

    
    
        : kragen@inexorable:~/mail ; ocaml
                Objective Caml version 3.10.2
    
        # let divide x = function 0 -> None | y -> Some (x / y) ;;
        val divide : int -> int -> int option = <fun>
        # let printResult = function Some x -> print_int x ;;  
        Warning P: this pattern-matching is not exhaustive.
        Here is an example of a value that is not matched:
        None
        val printResult : int option -> unit = <fun>
        # printResult (divide 9 3) ;;
        3- : unit = ()
        # printResult (divide 10 0) ;;
        Exception: Match_failure ("", 1, 18).
        #

------
plesn
Good point, but the debate is still in the "C++ vs Python" bounds. Haskell has
Hindley-Milner and Quickcheck and I think the debate is elsewhere: the cost of
abstractions and tools (just read another doc/paper to understand how to do
this) but also their benefits (scaffoldings and cranes while programming).

------
orblivion
I ride a bicycle in the city with a helmet, knowing that I do it in order to
ride a little more dangerously. It gets me where I'm going faster. When I'm
without a helmet in the city I ride very defensively.

I use Python and I'm very slowly getting into Haskell, I don't have much
experience with static typing, but I think that the analogy will apply when I
get used to it. I enjoy the safety net so that I can, in fact, be a little
more reckless in my coding. Experiment a bit more, get things done a little
faster, etc.

~~~
devinj
Static typing is like a helmet that forces a speed limit, too. It won't
necessarily help you experiment faster-- the common wisdom is that it does the
opposite, in Java/etc. style static typing.

~~~
Periodic
Which is why we need to work on dispelling the myth that static typing
requires explicit typing. Type inference gives you many of the advantages of
type checking without having to explicitly type every variable.

<http://en.wikipedia.org/wiki/Type_inference>

------
pasbesoin
Regarding the anecdote rather than the meat of the post, I drove for years
under all conditions without anti-lock brakes. These days, I still find myself
occasionally fighting them. I know very well how to control the car, including
through controlled skids, and that's worked its way deep into my reactions. In
extreme situations, the anti-lock brakes still sometimes throw me off and slow
my overall reactions, as I have to pause and adjust to their presence. I also
simply cannot perform some -- often useful -- maneuvers with them that I can
on a vehicle not having anti-lock brakes.

So... I can imagine some of the cab drivers, with years of driving experience,
having some difficulty adjusting to the _difference_ that anti-lock brakes
make, with a corresponding increase in effective reaction time and with
perhaps a surprising inability to negotiate risks as they have previously
learned to and expect to.

------
angelbob
This is true for "average drivers". The math is totally different with, say,
racecar drivers.

I think there's a strong parallel with programmers here, and whether you're
optimizing for average-case job throughput (or hobby throughput) or whether
you're optimizing something specific where safety or reliability is
specifically important.

------
rbranson
The comparison of static typing to anti-lock brakes is a bit off. Anti-lock
brakes are more like the function of an optimizing compiler (JIT or
otherwise). Unless you're on-top of your game all the time and have race car
driver-like reflexes, you can't beat it.

~~~
regularfry
It's not about beating it, it's about how having it affects your behaviour.

------
mkramlich
I worked on a 20 KLOC app of mine yesterday that has neither static type decls
or unit tests and yet is AFAIK bug free. This has been the rule and not the
exception in my experience. So I prefer to not have them since _in the general
case_ they are not needed and just add clutter and drag.

~~~
cabacon
I prefer to think of it as having bugs you just don't know about yet. Does
anyone use the app besides you?

~~~
mkramlich
Good perspective, thanks. And yes, many users other than me. Another way of
looking at it though is to say if a bug has never been encountered that
arguably it is not actually a bug and/or it doesn't matter. Anti-Heisenbug? :)

