
I like strong typing and compilation errors - rayvega
http://ayende.com/Blog/archive/2010/05/05/i-like-strong-typing-and-compilation-errors.aspx?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+AyendeRahien+%28Ayende+%40+Rahien%29
======
gruseom
People tend to pick one side or the other of this issue and then argue for it.
It's rare for anyone to change their mind, and even when they do, it's usually
just a boolean toggle to the opposite position. Most people believe (even if
they don't say it) that the opposite camp is, basically, stupider.

The entire subject is remarkably evidence-free. That's surprising; you'd think
(on the surface, at least) that it could be studied objectively. Of course, we
all have our individual experiences as programmers, but those aren't worth
much as evidence, because we interpret our experiences to suit our pre-
existing belief. Indeed, we don't even notice experiences that contradict it.
(I've seen static typing proponents go on about how compilers catch bugs and
then spend hours tracking down an InvalidCastException.)

In light of the above, I'm more interested in hearing what people have to say
in favor of the position they _disagree_ with. The debate is too tiresome
otherwise, entirely predictable.

Although I currently favor dynamic languages, I recently started the thought
experiment of asking myself, when fixing a bug, whether a good type system
would have caught it. Certainly there are times that the answer is yes (though
not always). The difficulty, of course, is whether the aggregate benefit would
outweigh the cost.

~~~
nostrademons
I don't really have a strong preference either way. The bulk of my
professional work is in JavaScript with a fair amount of Python and C++ thrown
in. I dislike the C++, but that's probably because the type system is brain
dead rather than because the type system is static. I do most of my hobby
hacking in Haskell, which has about the strongest type system imaginable. I'm
hacking on a programming language of my own design, which will have static
typing, but not to catch errors. I want static type inferencing because it
lets the compiler generate usable, machine-checked, cross-referenced, auto-
updating _documentation_ from my source code, without having to update this
myself.

I've found that I rarely have type errors in dynamically typed languages, _as
long as I program as if they were statically typed_. For example, if my JS
function _only_ takes strings or objects with certain fields, I just document
those and I almost never make mistakes with them. However, if I start defining
functions that return string|int|bool, _then_ I start getting confused. Do
this often enough and it becomes essentially impossible to reason about my
program.

Ironically, I've found that a good portion of my bugs in statically typed
languages are type errors, in the form of null pointer exceptions. Haskell's
Maybe type is the way to go here; yeah, it makes looking things up in a dict
inconvenient, but I can't count the number of bugs I've avoided by being
forced to deal with nulls up-front and not having them pollute the rest of the
program.

------
colonelxc
I'm glad I actually read the article, because while I too like strong typing
and compilation errors, but I don't want to be associated with programmers who
do things like this:

> _Today I had to modify a piece of JavaScript code. The code used return a
> single string, and I needed to modify it to return an array of objects.
> Using C#, it would have been easy, change the return type, hit the compile
> button, fix the errors, rinse & repeat until it compiles._

The compiler does not save you from having to think, and like InclinedPlane
says, compilation doesn't 'prove' correctness, only shows you that the
compiler could at least sludge its way through your code.

The code should pass some mental unit tests of expected inputs and outputs
before you even make the change.

~~~
liuliu
It is interesting to observe that TDD (or our intelligent IDE) actually makes
programmers never think. They tend to develop in more ad-hoc way: Google some
example code snippet, change the order and play around with some parameters,
fix the Eclipse "syntax error" hint and try it out until it works.

EDIT: yes, it is just plain wrong, no excuse. But I am trying to point out
that it truly happened and I am curious about why or how.

~~~
WalterGR
Hogwash.

No good developer does what you describe, no matter what tools they use.

~~~
InclinedPlane
Good? No. But making a living writing code, maybe even important code? Far
more likely than you'd like to think.

~~~
WalterGR
> But making a living writing code, maybe even important code? Far more likely
> than you'd like to think.

I've _never_ seen developers who work this way: not in industry - not even in
college.

In my experience, the "mess around with the code arbitrarily until it works"
style described by liuliu is the programmer's equivalent of a moral panic.
Everyone talks about it and laments it, but it doesn't really happen.

------
btilly
I don't see the need for the invasive change. Given the problem that he had I
would have written a new function that returned the more complex data
structure, converted the old function into a wrapper around the new one, then
called the new function in my new code.

Much simpler. Much safer. Much less chance of breaking existing code. (Decent
unit tests could help verify this.) And you avoid duplication of logic.

If I wished to convert existing code to use the new function, I could do that
at my leisure. Furthermore if someone happens to be developing code in another
branch or at another site which expects the old function to be there, I don't
break them.

~~~
AndrewDucker
If you're refactoring a lot then your method leaves you with huge amounts of
extra code, which makes maintainability much harder, because you've got
multiple levels of indirection.

~~~
btilly
If even your internal modules are clearly separated into public interfaces and
internal stuff, then most refactorings won't need that level of care.

------
BoppreH
I find it rather risky to change something and expect compilers to catch all
the errors.

Anyway, the non-typed languages I use tell me the line of code where the error
occurred. Isn't that equivalent in this case?

~~~
ori_b
No; The line has to be executed for the error to show up in a dynamic
language.

Think of types as logical propositions, and type systems as theorem provers.
The stricter and more powerful the type system, the more exact and precise the
proof will be, and the more you can be guaranteed that things won't go wrong.

~~~
BoppreH
Of course it has to be executed, but it's either something that you are going
to execute yourself (as in pushing a button) or at least you are making an
easy way to trigger this function. If you are testing such code you make sure
to run it.

I understand that strict typing works by guaranteeing _some_ things won't go
wrong, but I can't see many meaningful situations where it wouldn't generate a
runtime error in a scripted language, or at least results that make the source
of the error painfully obvious.

~~~
wvenable
> If you are testing such code you make sure to run it.

Ahh, but that's not the problem. It's easy to test the code your changing,
it's a much harder problem to find and test all the code that depends on that
code. Having the compiler spit out every instance everywhere that you need to
fix due to a new type-mismatch makes this significantly easier.

Some dynamic languages will happily convert values from one type to another
even when that's not the desired result -- you might not get an error at all,
just some bad data you might not find until much later.

~~~
gte910h
>Some dynamic languages will happily convert values from one type to another
even when that's not the desired result -- you might not get an error at all,
just some bad data you might not find until much later.

This happens with algol style static languages too (And is one of the reasons
I find people arguing for Erlang instead of python more persuasive than those
instead arguing C++ instead of ruby).

You are confusing _strong types_ with _dynamic variables_. Most of the algol
languages have weak to medium type _strength_.

For instance, python has _much stronger types_ than C. However, it's variables
are all dynamic references.

------
InclinedPlane
If you rest on the premise that merely because your program _compiles_ it is
also _correct_ then you will face a career full of frustration and mediocrity.

~~~
darrenkopp
That's not the premise he's making. He's saying it's more convenient. Also, I
would think twice before referencing ayende and using the phrase "...[ayende]
will face a career full of frustration and mediocrity."

~~~
InclinedPlane
I don't doubt that this is just one tiny aspect of Ayende's development
practices, and in that context it's not necessarily even bad practice.

The problem I have with Ayende's statement is that it can seem like advice,
and there are a huge number of inexperienced developers for which that advice
is incredibly dangerous outside of the proper context.

------
pw0ncakes
Strong static typing is great. You can cut your runtime bug count by 70-80%
easily if you know what you're doing, which provides an enormous increase in
productivity. Also, type discipline seems to lead naturally to better
architecture. You have to build your data structures and functions from the
ground up, which tends to kill a lot of the sloppy thinking and nonexistent
architecture that you sometimes see in the dynamically-typed world (although
this can't be blamed on the languages, because a lot of users of such
languages write great code).

Dynamic typing wins on prototypes and small projects, but for a project of
more than 2000 lines, I'd be hard-pressed to see a case where dynamic typing
wins.

Of course, I'll add the caveat that _good_ dynamic typing is essential. Most
people think dynamic pwns static because they're most familiar with Java and
Python, but Java has shitty static typing (you have to declare types, and
moreover end up needing to subvert the type system to do anything interesting)
whereas ML and Haskell have awesome type systems.

~~~
btilly
Interesting. You say that after 2000 lines, people are better off with static
typing. But then you make it clear that this is only true if, instead of
comparing widely used static and dynamic languages, you compare widely used
static languages with best of breed statically typed languages that are not
actually in wide use.

Where would you say that the trade-off is between dynamic and static if you
stick with widely used languages? (From your comments about Java I think you'd
choose Python.)

Where would you say that the trade-off is between dynamic and static if both
are represented by best of breed representatives? Something like Erlang or
your favorite Lisp?

How does it change things if we take into account the widespread availability
of useful libraries for some languages but not others? (The infamous "CPAN
argument" for Perl being an extreme example.)

~~~
pw0ncakes
_Where would you say that the trade-off is between dynamic and static if both
are represented by best of breed representatives? Something like Erlang or
your favorite Lisp?_

Lisp is a great language, but I still think static typing wins at a certain
point for large projects. Type signatures (which are automatically inferred)
provide a certain amount of documentation, and static typing also makes for
cleaner and inherently more comprehensible interfaces.

When you have multiple programmers, when a lot of time is spent debugging, and
when internal APIs become essential, static typing begins to show its
strength. People can't just change interfaces willy-nilly and expect everyone
else to adapt; the compiler catches this.

