Functional Scala: Functions as Objects as Functions

Welcome back to the third episode of Functional Scala!
This time i want to take you for a short ride to some Scala internals and open the curtain for that arcane Function types i talked about the last episode. That said, this episode is more about some Specialité de Scala rather than about Functional Programming in general.

Remember that we’re able to define Functions simply by specifying a Function literal, consisting of the Functions parameter list and the Function body (delimited by that Function arrow =>)  and may declare that Function as a named value of a certain Function type:

val power : ( Int, Int ) => Int  =  ( base: Int, exp :Int ) => if( exp <= 1 ) base else base * power( base, exp - 1 )

There we go again! What you should recognize is an ordinary Funtion, which can by applied to two arguments each of type Int, resulting into another value of type Int. Thus the type of the Function is

(  Int,  Int  )  =>  Int

Nothing new here! We already knew, that every Function is an instance of a certain Function type!

But everything is an Object ?

You surely have heard about it. In Scala, everything is an Object. No primitives, no wrapper types, no autoboxing (at least not in front of your face). But what about our neat Functions? I mean, Functions belong to the functional world, objects belong to the object oriented world, right? Well, since Scala is an object functional Hybrid, it has to make a match between the two. And since every value is an Object in Scala, Functions are Objects, too! Simple as that! Huh?

FunctionN

It turns out, that every Function you’ll ever define in Scala, will become an instance of an Implementation which will feature a certain Function Trait (ok, if you have no clue what a Trait is, but may have ever heard about Java, think about Traits as a kind of an Interface on Steroids as a starting point and for the sake of simplicity). There is a whole bunch of that Function Traits, ranging from Function1 up to Function22. Wow, and why are there so many? Does the producers of Scala have come up with heavy artillery and spared no expense or effort in order to show the importance of Functions? Well, sort of. Since Functions are Objects in Scala and Scala is a statically typed language, it has to provide an appropriate type for every Function which comes with a different number of arguments. If you define a Function with two arguments, the compiler picks Function2 as the underlying type. If you define a Function with seven arguments, you’ll end up with Function7. And since there is a maximum up to Function22, that means you can’t define a Function which will accept 23 arguments or more – isn’t that a pity?

Let’s take a closer look! Remember that Function from the last episode which takes three parameters each of type Int and results into a boolean value, indicating whether that three incoming arguments form a so called Pythagorean triple?

val pythTriple :  ( Int, Int, Int ) => Boolean   =   (  a :Int,  b :Int,  c :Int  )  =>  {
    val aSquare = a * a
    val bSquare = b * b
    val cSquare = c * c

    aSquare + bSquare == cSquare
}

Now guess the Function Trait you’ll end up for that Function? If you haven’t picked Function3, you regrettably only won the second prize.
Ok, a Function with 3 arguments and you end up with Function3, a Function with n arguments and you end up with FunctionN. That’s all well and good, but what about the argument types? And by the way, what about the type of the Functions result? You certainly already hit on type parameters, and you’re right! Let’s take a look at e.g. Trait scala.Function3.  I will only show you the parts which are relevant for this episode:

trait Function3[-T1, -T2, -T3, +R] extends AnyRef {
    ...
    def apply( v1 :T1, v2 :T2, v3 :T3 ) : R
    ...
}

Do you already recognize your Function? It turns out that the three type parameters T1, T2 and T3 will take the type of the arguments, while type parameter R represents the type of the Functions result. Don’t worry about the leading sign in Front of the type parameters for now. They show you the kind of variance for each of them (while the arguments are contravariant, the result behaves covariant. But don’t bother – if you know about the Liskov Substitution Principle and the art on how to use subtypes in place of  supertypes in a proper way, you’ll gain a good intuition for what the variance of that type parameters try to express).

Now, for every tangible Function we define in our well known literal way, the compiler will come up with an instance of the appropriate Function trait, where the type parameters are parametrized with the given types of the arguments and the type of the Functions result. Wait a moment. But our Function already got a type. Take a look at the above example. The type of Function pythTriple clearly is

( Int, Int, Int )  =>  Boolean

Well, yes! But that is only syntactic sugar for the appropriate Function type that come into operation. It’ pretty the same as

Function3[Int,Int,Int,Boolean]

And yes, since one form of type declaration is only syntactic sugar for the other, you can use both interchangeably. So we could have also defined our Function this way:

val pythTriple  :  Function3[Int,Int,Int,Boolean]   =   ( a :Int, b :Int, c :Int ) => ...

Aye! But one thing left. Now guess what that abstract method apply is representing? Right, it’s the method which get’s called on Function application (so the Function body is going to reside within that method)! Ah, do you already smell another kind of syntactic sugar? It’s true, our well appreciated, mathematical touched Notation of Function application simply by enclosing the arguments in parentheses, following the name of the Function is again only syntactic sugar for calling method apply with some given arguments. So more funny mixing of those two kind of Notations is possible.

On the one hand, you could trigger Function application by explicitly calling method apply on a given Function:

val isPythTriple_3_4_5  =  pythTriple.apply( 3, 4, 5 )

And the other way round, you may also give birth to a Function by implementing an appropriate Function Trait and define its required apply method in terms of the function body. In our example, it’s Function3:

val isPythTripple2 : (Int,Int,Int) => Boolean = new Function3[Int,Int,Int,Boolean]{
    def apply( a :Int, b :Int, c :Int ) : Boolean = {
        val aSquare = a * a
        val bSquare = b * b
        val cSquare = c * c

        aSquare + bSquare == cSquare
    }
}

Beware of the temptations

As you’re free to define a Function in a more object oriented style by providing an anonymous implementation for a FunctionN like in the above example, or even by creating a new class which is extending a certain Function Trait (where the instances of that class constitute a Function, not the class itself), it’s very easy and tempting to introduce not only behaviour but also state, simply because a class allows you to declare not only methods but also fields. And since those fields may also be declared as variables (remember, Scala has to serve the functional and the imperative world), nothing prevents you to write a Function with side effects (that is, a Function which not only depends on its arguments, or not only produces a single value as the result of its application):

class Last( init : Int ) extends Function1[Int,Int]{
    var last = init

    def apply( x :Int ) : Int = {
        val retval = last
        last = x
        retval
    }
}

val last : Int => Int   =   new Last( 1 )

val x = last( 5 )     // x == 1
val y = last( 5 )     // y == 5
val z = last( 8 )     // z == 5
 ...
val a = last( 5 )     // a == 8

Ok, this is not a very helpful Function in its own, but it shows you some of the weaknesses, when it comes to the question if Scala promotes a functional style. At least, it doesn’t prevent you from writing impure, side effecting functions. As a reminder, a pure Function only depends on its argument, thus whenever you apply that function to a certain argument x, it always results to the same result f(x), no matter how often you apply that argument (this characteristic is clearly broken for Function last: if you look carefully at line 13 and 14, you see that the Function is applied twice to the same argument 5, but results to different values). This feature is sometimes stated as the Equality of Functions, as Function application maintains equality of their arguments. If  you strive for a formal, more mathematical description for that feature, a i can calm down your curiosity. It goes something like this:

x == y    <==>    f( x ) == f( y )

No, this is not a lecture in mathematics. But if you don’t take off now, we’ll coming to another interesting feature of pure Functions. As we stated above, we alway receive the same value every time we apply a function to the same argument. And this also means, that we may call that Function at any later time and still receive the same value, hence there is no notion of time in a Functional world. Ahh, and now we have full circle: If there is no notion of time, it doesn’t matter in which order i place my Function calls, i.e. in which order they get executed. That was one of the intriguing features of Functional programming when compared to the paradigm of imperative programming in episode one. In an imperative, state changing world i always have to be aware in which order the statements get executed. And if you take another look at the above example, since our Function is impure, the relevance of time slips in again (as you may see in line 17. For the result value to explain, it’s no longer sufficient to look at the function definition, but also to be aware of the order in which the function get’s called – in this case, which argument was applied to the Function the last time).

Quintessence

So if there’s is one thing you should remember from this episode, than it is the dangerous seduction of introducing state into your Functions, since you’re entirely free to mix the literal style and the underlying object oriented notation in every which way you want. As soon as there is state, there’s automatically an impact of time when it comes to execution. You can minimize that risk if you stick to the literal form when defining Functions, since it’s much more difficult to introduce state this way. Just keep in mind, that a Function always boils down to an instance (that is an object) of a certain Function type, at least under Scala’s hood. There’s no escape from it!


Addendum

Since a Function boils down to an Object in Scala, you may have wondered if there’s a similar solution for Java. And in fact, there are some libraries which aim to bring a breeze of functional programming to Java. You may take a look at lambdaj or Functional Java. I even wrote a library functJ on my own some time ago for experimenting on how to avoid as much boilerplate as possible when it comes to Function definition. As we will hopefully see in some of the following episodes, Scala provides not only a smooth integration of Function literals as syntactic sugar, but carries some more ideas of Functional programming to the Java platform.

Posted in Scala. 17 Comments »

17 Responses to “Functional Scala: Functions as Objects as Functions”

  1. Heiko Seeberger Says:

    Very nice post, once again!

    It is also very easy to create an impure (side-effecting) function using the function literal notation (literal style):

    scala> var evilMutableState = 0
    evilMutableState: Int = 0

    scala> val evilSideEffectingFunction = (x: Int, y: Int) => {
    | val result = x + y + evilMutableState
    | evilMutableState = result
    | result
    | }
    evilSideEffectingFunction: (Int, Int) => Int =

    scala> evilSideEffectingFunction(1, 2)
    res0: Int = 3

    scala> evilSideEffectingFunction(1, 2)
    res1: Int = 6

    • Mario Gleichmann Says:

      Heiko,

      thanks for your feedback!

      And again – you’re completely right!
      I wanted to preserve producing that kind of side effect until i reach the episode where i will take a deeper look into closures … :o)

      Greetings

      Mario

  2. Channing Walton Says:

    Very nice thanks. You should get yourself added to http://www.planetscala.com/

    • Mario Gleichmann Says:

      Channing,

      thank you very much for your kind words!

      Actually i would like to have my blog noted at planet-scala – therefore i wrote a mail some time ago to James, but unfortunately there was no reaction. I think he was to busy at that time or my mail simply missed him somehow.

      Maybe i will mail again, when i’ve got some more episodes to show … :o)

      Greetings

      Mario

  3. anehra63 Says:

    Thanks for giving useful information.

  4. Functional Scala: Closures « brain driven development Says:

    […] about the definition and some of the characteristics of common Functions within the first three episodes, let’s not waste any more time and take a look at another example of a Function, which is […]

  5. Functional Scala: Turning Methods into Functions « brain driven development Says:

    […] ( Int ) Boolean ) which almost looks like a function type (like Int => Boolean), but you may remember that this is only syntactic sugar for a Function Trait, e.g. Function1[Int,Boolean]. So in Scala, a […]

  6. Functional Scala – Mario Gleichmann « Another Word For It Says:

    […] Functional Scala: Functions as Objects as Functions […]

  7. Functional Scala: Curried Functions and spicy Methods « brain driven development Says:

    […] so no brained, that it’s of course already provided within the interface of Scala’s FunctionN […]

  8. James Cunningham Says:

    This post is a little ancient history, but I’m going through your tutorials (very helpful, by the way, thank you!) and feel the need to point out:

    x == y f( x ) == f( y )

    isn’t quite right. It isn’t necessarily true that f( x ) == f( y ) implies x == y. A tiny one-character nitpick, I suppose, but it *could* give someone the wrong impression of what a “pure” function is.

  9. Functional Scala: Curried Functions and spicy Methods « brain driven development | TechRetriever Says:

    […] It’s so no brained, that it’s of course already provided within the interface of Scala’s FunctionN […]

  10. Anonymous Says:

    Excellent article, well explained.

  11. Holger Peine Says:

    It’s a pity that the comment by James Cunningham above was initially misformatted, since that minor quirk might distract from its fully valid point:
    f( x ) == f( y ) does NOT imply x == y even if f is a pure function. There are many examples of pure functions where this implication does NOT hold, e.g. the sign function (which maps positive numbers to 1, negative ones to -1 and zero to zero).


Leave a reply to Mario Gleichmann Cancel reply