Saturday 6 October 2012

Scala : How functions are treated as objects

Hi friends,
        happy to share some interesting things studied from the on-line course Functional Programming Principles in Scala taken by the creator of Scala himself. Here I am trying to explain how functions are treated as primitive objects in Scala.

Consider Assignment of function
scala> def f(x:Int)=x*x  
f: (Int)Int

scala> var t:(Int)=>Int=f
t: (Int) => Int = <function>
We can also perform such an assignment as follows
scala> var t:Function[Int, Int]=f
t: (Int) => Int = <function>

similerly,
val y:Function2[Int,Int,Int]=(i:Int,j:Int)=>i+j
y: (Int, Int) => Int = <function> 

This gives insight to how functions are actually treated like objects in Scala.

In Scala, Traits Function1, Function2, ...Function22 are defined like follows
package scala
Trait Function1[T,F]
{
    def apply(x:T):F
} 
A function object of type (T) => F is an instance of subclass of Function1[T,F]
We can now define a function of type (Int)=>Int in this very basic way as follows.
class FunClass extends Function[Int,Int] {            
     def apply(x:Int):Int=x*x
}
defined class f
scala> val newFun=new FunClass()
newFun: FunClass = <function>

scala> newFun.apply(9)
res1: Int = 81
This is same as
scala> newFun(9)      
res2: Int = 81 
Now let us create an anonymous function
scala> val f= new Function[Int,Int] {
     | def apply(x:Int)=x*x
     | }

scala> f(9)
res2: Int = 81 

Now look at the apply() function.What happens if The apply itself a function object which with an apply() function as its member? It will lead to an infinite expansion when we create any function objects.

scala> def f(x:Int)=x*x                  
f: (Int)Int

scala> f.apply(9)
<console>:6: error: missing arguments for method f in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
       f.apply(9)
       ^
Why we could not call apply() of object f? No its not. f is not a function object here. Now look back to our first try
scala> var t:Function[Int, Int]=f
t: (Int) => Int = <function>
Here a function object corresponds to f is generated which is an "anonymous function object" and is assigned to variable t while executing these kind of assignment statements. Here it is a simple definition for "eta expansion".

Friday 5 October 2012

Scala:Type parameterization

Polymorphism in Scala can be achieved through type parameterization. Let us define class g with attributes x,y as integers as
scala> class g(val x:Int, val y:Int)
defined class g
We can use Type parameter like follows
scala> class g[T](val x:T, val y:T)
defined class g

scala> val obj=new g[Char]('a','b')
obj: g[Char] = g@a53564

scala> obj.x
res11: Char = a

scala> obj.y
res12: Char = b

We need not specify the type parameter explicitly like that, the Scala compiler  can infer the Type from function parameters
scala> val obj=new g('a','b')
obj: g[Char] = g@a53564

scala> obj.x
res3: Char = a
scala> val obj1=new g(1,2)
obj1: g[Int] = g@a53564

scala> obj1.y
res3: Char = 2
Now we can play a bit
scala> val obj=new g(1,true)          
obj: g[AnyVal] = g@11d95

scala> obj.x
res1: AnyVal = 1

scala> obj.y
res2: AnyVal = true
Notice that  val obj=new g(1,true) doesn't cause a type mismatch error even Value 1 is of type Int and true is of Boolean while both parameters are expected to be of same type. The reason is that, Boolean, Char, Int etc. are Subtypes of AnyValue.Here The compiler inferred the type as AnyValue looking at the parameters passed.

We can also have multiple Type parameters as follows
scala> class g[T,H](val x:T, val y:H)
defined class g

scala> val obj=new g('A',9)
obj: g[Char,Int] = g@14f7121

scala> obj.x
res10: Char = A

scala> obj.y
res11: Int = 9
We can define functions of parameterized type like follows
scala> def f[T](x:T):Unit=print(x)
f: [T](T)Unit

scala> f[Int](6)                  
6

scala> f(6)                  
6

scala> f("ssss")                  
ssss