I never felt the need for TDD or such… until I used Lua. I was drowning in bugs for a tiny 200 lines program! I just couldn't finish. Then I wrote some visualization code, then more of it, until I had the equivalent of a domain specific debugger. It worked. I found my mistakes, and corrected them. Then I though "that is where TDD comes from".
A statically typed languages such as Ocaml or Haskell would have caught the vast majority of my mistakes right away. Heck, even C++ would have helped. In my experience, writing code that "mostly works" is faster with a statically typed language. So many trivial tests you don't have to write, so much debugging you don't have to do…
> Second, most bugs I've experienced in large code bases using a dynamic language are not the sort that would be caught by most typed languages.
So, no Null pointer bug?
Also don't underestimate the number of domain logic errors that could have prevented by encoding the domain logic into the type system. Type systems can encode many invariants, they're not limited to "this is a bool, I wanted an int".
"The only arguments that hold water, in terms of programming language suitability, are bold, finished projects." http://t.co/ahOBAnXZ18
Here are some papers that underbuild this argument: http://page.mi.fu-berlin.de/prechelt/Biblio/jccpprt_computer... https://files.ifi.uzh.ch/rerg/amadeus/teaching/seminars/semi...
You can doubt, but I'm speaking from some experience with both. That doesn't necessarily mean I'm right, of course, but take it for what it's worth.
Great as it is, the language itself (and functional programming in general) tends to be pretty opaque to most programmers. Purity is powerful; we've all heard it before so I'll spare us yet another apologia. But, as my time spent TAing an introductory course in Scheme taught me in agonizing detail, purity is painful, too. Most people just don't naturally think of processes as a composition of mappings from values in a domain to values in a codomain. For better or for worse, the "process as widget-fiddling" way of thinking comes much more easily.
This is most difficult to accept, because I do.
It's like programmers are divided into two camps: those who think procedurally, and those who think mathematically. I have noticed lately how this can influence API design, down to things as simple as this:
void latin9_to_utf8( std::string& latin9str);
std::string latin9_to_utf8(const std::string& latin9str);
The first interface is a design mistake: it encourages side effects, and requires more code to use in practice. But it is also a very natural one: you want to convert strings, so you write a function that converts strings (KISS). The second interface is better, but more convoluted: instead of just converting strings, it returns converted strings.Guess which ended up in a real program I worked on…
Where things really fall apart is using recursion instead of loops. Especially when the time comes to mention tail recursion.
Though for this particular mistake, it may have come from some misguided notion about performance (like perceived overhead of constructing a string then passing it up the stack).
As for things like recursion and closures… I just avoid them because I know my colleagues will recoil in horror with such uselessly indecipherable excess of cleverness.
The size of Sonatype Snapshots and Central is roughly around Rubygems.org size I think. But so so so many Ruby projects are half baked, while so many public JARs are so much more mature (if often not very pleasant to work with).
This says something about what tooling does to people. Haskell people say they think in types but this make it look wrong. It would appear they are less good with types when you take their tools away. People working primarily in dynamic language probably end up writing programs that are mostly correct in that respect because they have no other choice to become productive.
This looks similar to how people who are raised in clean environments are more vulnerable to bacteries. This is not a bad thing: we still improved life expectancy a lot with hygiene and antibiotics. But we got weaker immune systems and allergies.
In my opinion, the maintainability of a codebase is not that much a function of the language, but of the architecture and structure of the code.
That said, I have been in industry for over a decade in a half, and the most miserable, hellish experience I ever had was dealing with a large (100k+) non-trivial consumer facing Python application. It was a special type of pain, with novel errors happening in production on a regular basis 4+ years into the project. Refactoring was horrifically risky, and the analysis tooling stack is AWFUL... to the point that when used, it was often outright wrong.
I will gladly give up those cost savings on the leading edge, to have a product I can actually maintain in the long term. I suspect this inability to maintain apps writing in certain dynamic languages is why they have culture bias towards starting over (and being proud of it, "version 2.0, rewritten from scratch!")... which I found a bit shocking at first versus C, which would trend far more toward refactoring.
* Sometimes, the time it takes to build something in a statically typed language is much longer. Long enough that by the time it is built it might not matter because somebody would have built it in node.js, ruby, or python. I really depends on the market.
* Type mismatches in a Python program are not the biggest and deadliest bugs. Unit tests and integration tests (that should be there anyway) should catch those well.
* Often static type languages that have pointers (C, C++) hide much deadlier and dangerous types of bugs -- pointer bugs like "wild pointers".
* Static type language that don't offer protocol checks also can't easily detect bugs where you open a file handle, close it, then read from it. It knows it is a FILE or some iostream but it doesn't help much there. I've heard other more advanced languages have something in place to handle that.
* The above point coupled with being able to use the REPL on a production system and code has saved significant debugging time. In a complex system there could be an interaction that is hard to reproduce and this one system is in that funky state. Can log in via SSH into it, edit the code to add some debug statements and reproduce it again.
In summary, I would like Python to have a standard type annotation syntax that good linters will be able to check for and IDEs will know how to read and use. But it would not be at the top of the list of features I would like Python to have next.
EDIT: (sorry, last sentence should have said "it would not be" instead of "it would be")
You can fix catch these errors with a suitably advance type system; but often a simple construct like Python's with-statement works well for most cases, too. (If you have higher order functions or macros or RAII, that kind of construct doesn't need to be build into the language, even.)
Not that it matters in most cases though. A programmer picking a language for a project does not realistically have access to the full design space of type systems. If the only implementation of a language with some type system feature is an interpreter for a core calculus written in Agda and not touched for the past several years, that feature is effectively unavailable. Most programmers are not in the business of designing and implementing custom type systems (and associated languages) and probably wouldn't gain enough from it for it to be worth the work of learning how anyway.
I think that there are two reasons why good data on this is not forthcoming.
The first is that for a long time the dominant statically typed languages have been C++, which forfeits most of the potential advantages of static typing by also being weakly typed, and Java, which handles types somewhat better (while by no means being state-of-the-art) but brings its own productivity challenges.
The second is, the kinds of enormous long-lived maintained-by-50-full-timers hoary old enterprise applications that I think most fans of static typing have in mind when they say, "I wouldn't want to maintain that in a dynamic language!" aren't often written in dynamic languages. This in and of itself could be seen as evidence that dynamic languages really are unsuited to the task.
Perhaps the more interesting evidence, though, is the tendency of what few larger- and longer-lived dynamic projects there are to become famous for messy code. This hits at what I think fans of static typing are really talking about - that doing any sort of large-scale refactor in a dynamic language is a terrifyingly error-prone experience. You need to rely on ever-fallible humans to have written tests that exercise all relevant code paths in order to verify that the refactor was successful in even the most basic terms. For someone who's used to having the compiler quickly, reliably and exhaustively provide the same feedback, having to fall back on the source of all known bugs (programmers) to do the same job leaves one feeling a bit exposed.
There have been attempts at measuring the effect of type systems, see for example this excellent presentation for some references: http://www.slideshare.net/Felienne/putting-the-science-in-co.... One of the studies mentioned here does claim that, other things being equal, static typing helps find bugs quicker.
Why be so condescending? Why assume things you have no way of knowing?
What do you want me to say? I have no illusions about the integrity of my rhetoric—it has none. It was a statement made without much thought based on my experience. It does not require or request your approval.
People make this sort of claim all the time, but my personal experience has not borne it out, and I have seen no data to backup this claim which would override my personal experience.
First, I find I have to write tests nearly as religiously in statically types languages, so I don't find that a convincing argument.
Second, most bugs I've experienced in large code bases using a dynamic language are not the sort that would be caught by most typed languages. On this point there is even some data that backs up my personal experience (http://vimeo.com/74354480).
Third, writing code with a static language takes more time in my experience. Maybe it prevents a tiny fraction of bugs, but for most things I'll take saving significant time and cost over preventing 3% of bugs (I made up that number).
In short, I'm not sold on these arguments for static typing.