Wednesday, January 26, 2011

Not Your Type

Not too long ago, I was asked by a friend why I like Scala's type system and how it helps develop software faster (relative to dynamically typed languages, like Ruby). The short answer is that it doesn't; the slightly longer answer is that that isn't the point. An effective type system is more about making the computer help you get your code right, because throwing $125,000,000 down the drain when one person uses metric and the other English units looks bad on the next budget request.

I suspect that most detractors of type systems are doing so from the perspective of weak type systems (like Java's), which really does get in the way as much, if not more, than it helps. A more powerful type system (e.g. Haskell's or Scala's), however, can actually make it a compile error to make some subtle errors. As an example, here's some Scala to make Velocity a type defined by Meters/Seconds:


class Meters(val dist : Float) {
def /(time : Seconds) : Velocity = { new Velocity(dist/time.magnitude)}
}

class Seconds(val magnitude : Float)

class Velocity(val magnitude: Float) {
override def toString() = magnitude + " m/s"
}

class Feet(val magnitude : Float)

With that definition, you can define something of type Meters, divide it by something of type Seconds and get a Velocity. Ok, so far so good, but that doesn't seem to be that helpful... until you find that you can not multiply the Meters by a typeless unit or accidentally by Feet! Now, you may be thinking, "Hey, that's still getting in my way! I have a parameter in Feet and I don't want to bother changing it to meters!" That's where the second trick up Scala's sleeve comes in, by providing a way to implicitly convert from Feet to Meters.

By adding this little snippet of code:
implicit def feetToMeters(feet : Feet) = new Meters(feet.dist * 0.3048F)
we can now divide Feet by Seconds and get Velocity in meters / second!
So now, these two statements print the same value:
println(new Meters(1000)/new Seconds(60))
println(new Feet(3280.8399F)/new Seconds(60))


And helping avoid turning a Mars Orbiter into a Mars Crasher is just one more reason why I really like Scala.

No comments: