« See all posts

Funny Consequences of "Functions are Objects" Rule in Scala

Posted by Alexander Dymo on September 08, 2007

Scala language is an unique combination of interesting language features and clear and concise syntax which is so rare in the world of programming languages.

Scala is truly object-oriented. This does mean that everything is an object, even functions. Err, functions you'd ask? Yeah, functions are indeed objects but that wasn't a surprise for me because I've seen and used that in Javascript. But function inheritance indeed was a surprise.

How can that be possible? Martin Odersky gives an example that functions with one argument in Scala are objects that mix this trait:

trait Function1[-A, +B] {
  def apply(x: A): B
}

Traits are the Scala implementation of mixins. For C++ guys mixin is just a multiple inheritance. For Ruby guys trait is more like a module. The difference is that in Ruby you'd "include" the module into your class and in Scala you'd "extend" the class with a trait.

In the example above "-A" means that function that has AnyRef as an argument inherits a function that has a String argument. Take a look at this magical example:

object MyProg {
    def doSmthStr(a: String): Int = a.length
    def doSmthAny(a: AnyRef): Int = a.hashCode
    def compute(function: AnyRef => int) = {
        function("Haha")
    }
    def compute2(function: String => int) = {
        function("Haha")
    }
    def main = {
        // not possible because doSmthStr is of type String => int
        // which is supertype of AnyRef => int
        compute(doSmthStr)
        // possible because doSmthAny is exactly of type AnyRef => int
        compute(doSmthAny)
        // possible because doSmthStr is exactly of type String => int
        compute2(doSmthStr)
        // possible because doSmthAny is of type AnyRef => int
        // which inherits String => int
        compute2(doSmthAny)
    }
}
MyProg.main

Isn't that cool, the function doSmthAny with AnyRef (aka Object in Java) argument inherits the function doSmthStr with String argument and therefore can be used whenever we need doSmthStr. Amazing!!!

Even more amazing is when the return types in those functions are different. For a function to be the subtype of another function we not only require its argument to be a supertype, but its return value to be a subtype. Citing Scala by Example book:

function S=>T is a subtype of S'=>T' if S' is a subtype of S and T is a subtype of T'

where S=>T is a function defined as:

    def function(arg: S): T
Next: More Surprises in Scala: Covariance and Contravariance
Previous: Scala: a Pleasant Discovery