Our Fathers’ Faults – Scantly Typed Language

Scala tries to help the programmer in many ways. Verbose and repetitive code can be often syntactic-sugarized into concise statements. This is very convenient but encourages the programmer to produce write-only code. Let’s talk about types. In many contexts, you can is very good at inferring types. Consider

val n = 1

This Is the most obvious case, you don’t need to specify Int because the language manages to infer the type of the variable from the type of the expression to the right of the equal sign.

Compare with:

val x = foo(n).map( bar )

This is quite simple for the compiler since it has in hand all the involved types and can quickly find the type that x must have to have a well-defined statement of the language.

Dissimilar from the compiler, the human reader is required to go to lookup foo and bar to understand what is the type of x.

Scala may infer types in even more complex cases, such as the function return type. E.g.:

def twice( x: Int ) = 2*x

The language is perfectly capable of decorating the definition of twice with the Int return type by looking at the function body. Also when things get more complicated the language manages to find its way –

def foo(n: Int) = {
   some code
   if( condition ) {
      other code
      <here a return value>
   }
   else {
      obscure code
      yy match {
         case A =>
            codecode
            <another return value>
         case B =>
            morecodecode
            <yet another return value>
      }
   }
}

Without complaining the language infers the return type for foo. If all the return expressions have the same type, then that is the return type, otherwise, the language looks up the inheritance tree of the different type for a common ancestor.

You got the picture. But consider the example below –

def innocentLookingFunction( n: Int ) = {
    if( n < 3 == 0 ) {
        List( n )
    }
    else {
        Array( n )
    }
}

What is the return type? Guess what… java.io.Serializable. This is because Array is a java type, not a Scala specific type and Serializable is the first common ancestor for List and Array. Funnier:

def anotherInnocentLookingFunction( n: Int ) = {
    if( n < 3 == 0 ) {
        List( n )
    }
    else {
        Map( n -> n.toString )
    }
}

Has the following return type: scala.collection.immutable.Iterable[Any] with PartialFunction[Int,Any]{def seq: scala.collection.immutable.Iterable[Any] with PartialFunction[Int,Any]{def seq: scala.collection.immutable.Iterable[Any] with PartialFunction[Int,Any]}}… enjoy.

Since programmers are usually unreliable, especially when bound to work long and stressful hours, mistakes happen and an oversight could turn in a really odd behavior or compilation failure at a completely different place.

Summing it up – there are basically two problems with letting the compiler infer types. First, the code may be obfuscated if the type cannot be easily figured out by the human reader. Second the inferred type might not be what was intended by the writer, leading to subtle bugs.

lesson learned Always declare the type of objects unless when the type is obviously clear by looking at a single line of code. By obvious I mean obvious in the expression, not in naming.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.