Thursday, December 29, 2011

Scala's implicit need to be handled with care

Quick post when using Scala's implicits. These constructs are really useful in the manner that they allow the user to create rather complex expressions in type design & bridging frameworks in the Java world. However, i did find some oddity when i was playing with it and found something interesting, to me.

Let's begin with a simple example.

scala> object holder {
     | trait Foo {
     | implicit val x = new Foo { override def toString = "trait foo" } }
     | object Foo {
     | implicit val y = new Foo { override def toString = "object foo" } }
     | }
defined module holder


scala> import holder.Foo
import holder.Foo


scala> def method(implicit foo: Foo) = println(foo)
method: (implicit foo: holder.Foo)Unit


scala> method
java.lang.StackOverflowError
at holder$Foo$$anon$1.(:18)
at holder$Foo$class.$init$(:18)
at holder$Foo$$anon$1.(:18)
at holder$Foo$class.$init$(:18)
at holder$Foo$$anon$1.(:18)
at holder$Foo$class.$init$(:18)
at holder$Foo$$anon$1.(:18)
at holder$Foo$class.$init$(:18)
at holder$Foo$$anon$1.(:18)
at holder$Foo$class.$init$(:18)

The interesting thing is that the Scala runtime can't seem to make up its mind whether to invoke the "x" or the "y" when its being looked up in the call to "method".

Another example would be related to Scala's package objects. To see how the problem can manifest itself, here's an example with a file named package.scala in Scala's convention and here are its contents:

package object foo {
  implicit def foo = new Foo
  implicit def foo2 = new Foo
}
package foo {
  class Foo {
    override def toString = "FOO!"
  }
}

when you run the compilation via scalac, it generates a directory foo and dumps the class files there. Nothing to it. Now run scala and use the implicitly function and you'll see what i mean.

Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_29).
Type in expressions to have them evaluated.
Type :help for more information.


scala> implicitly[foo.Foo]
:8: error: ambiguous implicit values:
 both method foo in package foo of type => foo.Foo
 and method foo2 in package foo of type => foo.Foo
 match expected type foo.Foo
              implicitly[foo.Foo]

This isn't Scala's fault, really; because the compiler can't possibly know what you plan to do with it but it certainly is something you should be aware of and i do think this is a good thing (rather than having the compiler just forget about it)

The idea is to really limit the scope in which the implicits exist so as to reduce the amount of pain you have to go through when debugging

Sunday, December 18, 2011

Scala's type erasure in writing functions

Wanted to write a quick post to anyone whose out there interested. The topic of this post has to do with type erasure in Scala. I won't dwell on history but to get an idea what it is (other than googling or ref the wikipedia) you should read this well written article here.

I like to use an example to illustrate something here. Whilst playing with Scala, i find myself writing code like this 


class MyTest {
 def printSomething = println("blah blah blah")
 def compute1Value = 41 * 41 
 def compute2Value = (41*41*2, 1)
}

object SimpleTest extends App {

def test1(a : {def printSomething: Unit ; def compute1Value: Int; def compute2Value: Tuple2[Int, Int]} ) {
.... // do something 
}
I thought nothing special here. Compiled it and it works. But i thought i should be able to write something more generic than that because the structural subtyping technique here is REALLY useful in real world applications but there're caveats because of type erasure (this post isn't about that)

So i proceeded to modify the type of 'a' in 'test1' to become like this


...
def test1(a : {def print1Line: Unit; def fn1:Function0[Int]; def fntuple2: Function0[Tuple2[Int,Int]]}) {
.. // do something
}

But this didn't compile. Hmm...(honestly, WTF was the word that came to my mind) what happened. Afaik, it should work because i have a valid function definition on both LHS & RHS of the equation. However, after figuring out what happened by examining the java bytecode output i realized it and the following definition works


...
def test1(a : {def print1Line: Unit; def compute1Value:Int; def compute1Value2: Tuple2[Int,Int]} ) {
... // do something
}

Mystery solved. Don't get me wrong here but you should probably be able to find the answer by examining the Scala Language Specification &  still i chose to de-assemble the code and from the output below you should be able to guess that the return type was determined and instead  embedded into the signature of the function.


...
public int compute1Value();
  Code:
   0: sipush 1681
   3: ireturn

public scala.Tuple2 compute1Value2();
  Code:
   0: new #24; //class scala/Tuple2$mcII$sp
   3: dup
...

Alternatively, the following code works too


class MyAnonFnClass {
  def print1Line = println("blah blah blah")
  def fn1 = new Function0[Int] {
              def apply() = 41 * 41} 
  def fntuple2 = new Function0[Tuple2[Int,Int]] {
                  def apply() = (41 * 41 * 2,1) }
}

object SimpleTest extends App {
def test1(a : {def print1Line: Unit; def fn1:Function0[Int]; def fntuple2: Function0[Tuple2[Int,Int]]}) {
... // do something
}
This definition of "test1" is what i like better but the definitions of "fn1" and "fntuple2" is somewhat awkward. Still, some say it doesn't look right ... there're better ways of writing this and an example is that of James Iry at stackoverflow