On the first day of NDC London 2013 there was a cage match between Gary Bernhardt of Destroy All Software - known for the WAT talk, and Useing You're Type's Good - and Jon Skeet of Google - known for his "C# in Depth" book, and his activity on Stack Overflow. They were discussing the topic of dynamic versus static typing.
Jon Skeet started by asking, what is it that Ruby can do and C# can't. In response Gary tried to show stuff that seems idiomatic in Ruby, and relies heavily on the dynamic nature of Ruby. Where the discussion went a bit south was when Jon Skeet tried to do all that in C#, and did the ugliest hacks just to make it work, while relying on C# features that are explicitly there to make C# a bit more similar to dynamically typed languages. All that proves to me, is that C# is trying really hard to be Ruby, and sucks at it. So what? Besides, we all know that it's not true at all.
I personally have changed back and forth between statically typed and dynamically typed languages quite a lot, and both hated and loved them every time I did. After a while I started to have very exciting discussions between the left and right side of my brain. (Rest assured: we are not schizophrenic, although the rest of this blog entry may suggest differently.) The odd thing is that both of me seem to have realized that the other has interesting points to support his beliefs, but neither of me is willing to give up any of it. Instead I kind of became the devil's advocate on the matter. (And that's really funny if you know what my last name - Ördög - means in Hungarian.) Whenever I meet anyone who seems to strongly believe in one or the other, I try my best to convince them that they are completely wrong and total idiots. So if you came here with the intention of finding out which one is better, here is a final clue: you won't! However I promise there is an interesting conclusion at the end.
Let's give a name to my brains, just to make the rest more fun: Steve is a firm believer in static typing, while Dan is this ruby / nodejs fan boy.
I think that most probably by asking the question "static or dynamic" we are asking the wrong question. The right question is how could we combine the virtues of both. The reason this debate has not been settled is because there is no good answer. Every time I switch between the two I always run into the same problem: the tricks I use with one don't work with the other. When you switch from static to dynamic or back, you need to reinvent your tool set, your methods, and so on.
The arguments regarding the presence or absence of certain tools like InteliSense or refactoring browsers are pure non-sense. Every programmer should have the best tools money can buy, and if he needs something that no one else has created before, he should do so. The thing is though, that easier implementation of refactoring tools comes at a price of a crufty code base. Extracting a method in Ruby is so easy to do by hand, that even though RubyMine does have a shortcut to do that it does not save me as much time as the same tool does when I write Java code. On the other hand a Java programmer needs to know at least a hundred IDE shortcuts to become effective. Different languages require different tools for effective coding, and it's complete nonsense to say that a language is better since there is a tool for it, that does not exists for another language. Especially when it would not even make sense to have a tool like that for that other language.
Advocates of static typing usually also mention types being valid unit tests. In C++14 one can add measurement units to numbers, which not only makes the code a lot more readable, but in light of the Mars Climate Orbiter fiasco also seems like a proof of how static types could save millions of dollars. The only problem with that argument is that a good integration test between the two systems would have clearly pointed out the problem. Honestly I don't buy into that reasoning, and I believe that the number of errors static typing can catch is minuscule when compared to tests written as part of a good test driven development process. The only advantage of static types over tests is that types are non optional, while tests are. It's a lot harder to circumvent the type system by accident, than it is to leave out an important test case.
When it comes to dynamic typing versus static typing the real decision for me is less and more expressive code versus more information inside the production code and less opportunities for crazy hacks. Dynamic languages follow the philosophy, that it's the size of the code base that matters when we try to minimize maintenance costs, while the philosophy of static typing is that a little more code in return for being able to reliably determine all execution paths is the key to maintainability. Which one is more important can depend on the circumstances.
For example I would rather inherit untested code in a statically typed language. But if I take a good unit test coverage for granted, than I do have a preference for dynamic typing. With more flexibility comes more responsibility, but I expect my fellow developers to act responsibly. Obviously that also means, that if I were given a bunch of university students with little experience as a development team, I would rather use a statically typed language. It won't prevent them from making a huge mess, but at least it makes it a bit harder. For similar reasons I can see why large companies seem to prefer static languages: you just can't hire thousands of talented developers, and even if you could, it's hard to follow implicit rules with a group that large. Smaller start up companies on the other hand would have a small number of highly experienced developers and the flexibility provided by dynamic languages might just give them the competitive edge they need while struggling to meet a very short time to market expectation along with serious limitations on available resources.
As for dynamically typed languages: I'd like to see a tool that runs all unit tests against my function, and deduces the common interface used by the objects that have been passed to it. That would improve auto complete in dynamic languages quite a bit. Maybe the possibility of optionally specifying a required interface for each parameter of a function would also be nice, as long as that type check only checks if the necessary functions are there, and does not require me to explicitly state that a class implements a given interface. Those tools would kind of give me the power I miss from statically typed languages.
Actually this concept can be generalized further: although it's not possible to determine all execution path with static analysis in case of dynamic languages, but it's a reasonable expectation that by analyzing the program while the unit tests run we will see all of them. I think that this observation could be used to create a wide range of tools for dynamically typed languages, that people coming from a statically typed background miss when they encounter dynamic languages.