I was reading the article “Twitter on Scala” that appeared on artima a few days ago. I was really interested to hear what they had to say about it, since I have been looking at Scala a bit over the past few months. I was also curious to hear what exactly they had to say about Ruby and their reasons for wanting to move over to Scala (at least for parts of Twitter).
I had expected to hear the usual complaints about Ruby, which generally revolves around performance and the runtime, but if that was their only problem then why didn’t they just move to running JRuby on the JVM? They would have gotten some of the perf they wanted, along with the benefit of having a more mature garbage collector. And don’t get me wrong, those complaints were there, but there was another interesting comment made by Alex Payne.
As our system has grown, a lot of the logic in our Ruby system sort of replicates a type system, either in our unit tests or as validations on models. I think it may just be a property of large systems in dynamic languages, that eventually you end up rewriting your own type system, and you sort of do it badly. You’re checking for null values all over the place. There’s lots of calls to Ruby’s kind_of? method, which asks, “Is this a kind of User object? Because that’s what we’re expecting. If we don’t get that, this is going to explode.” It is a shame to have to write all that when there is a solution that has existed in the world of programming languages for decades now.
Before people start crying foul about the “kind_of?” checks in Ruby, yes, we all know that this is not the “Ruby Way”. We are all fully aware that if you are doing “kind_of?” checks all over the place then you are doing it wrong. But what is interesting to me in this comment is talking about creating a type system in unit tests. I had honestly never really thought about it in that way, and so when I read that comment I had one of those long “hmmmmmmmmmmmmmmm” moments.
We all know that unit testing is absolutely important for any program, but testing takes on a new level of importance in dynamic languages because many times we are doing a lot of the checking that happens at compile time in statically typed languages. But are we really trying to recreate a type system?
I know that even in dynamic languages, when I write a method I often have an idea of what type will eventually be passed into the method, even if I am doing no type checking. Maybe I am still living in a static mindset, or maybe this is typical among developers in dynamic languages? I love the power that dynamic languages provide me, but I also realize that a good portion of my code would look almost identical in a statically typed language. Especially in a statically typed language such as Scala or F# that have almost magical type inference.
But anyways, I want to hear some feedback, and here are a few questions to get you started.
When we write unit tests in dynamic languages, are we doing some of the work that statically typed language compilers do for us? I would argue yes. And maybe it is just because of my static background, but I would pass common types that I expect to be given to methods, in order to check correctness. In a statically typed language I would do the same thing, but I wouldn’t be checking for things like missing methods, misspelled methods/variables, etc…
If we are, then aren’t we doing it much less reliably? Again, I would say yes. With a statically typed language compiler, you really have very little chance of missing basic type errors. The bar is much higher in dynamic languages.
If this is the case, then would it be a better balance to have a static language that would let us fall into dynamic typing when we need it? This is a much tougher question. What advantages of dynamic typing would we lose when we have to think about using it? What would we lose in the interaction?
And finally, are we trying to recreate a type system? I’m not sure I’d go so far as to say that we are trying to recreate a type system, but I think that we are often thinking of concrete types as we develop our code. And when we test, I think that this is manifest. I want to hear your thoughts on this though.
So leave a comment (or better yet, respond in your own post), what do you think?