4

Can anyone re-write this code to do the same thing but without any compiler warnings please:-

object TestTypeErasure {

  def main(args:Array[String]) {

    def myFunction(myObject:Any):Boolean = {
      true
    }

    val myVariable: (Any => Boolean) = myFunction

    myVariable match {
      case function:(Any => Boolean) => println("Match")
    }

  }
}

Thousand thankyous

Keith

Update!!!!. Sorry making a real hash of this. Its my first question on SO

Just to let the gurus know I have tried something along the lines of this also to no avail:- (Can't compile it)

object TestTypeErasure {  

    def doTest(parameter: Any) = {  
        parameter match {  
            case function:Function1[_, _] => function("Whatever")  
        }  
    }  

    def main(args:Array[String]) {  
    }  

}  

I get error :-

TestTypeErasure.scala:6: error: type mismatch;
  found   : java.lang.String("Whatever")
  required: _
    case function:Function1[_, _] => function("Whatever")
                                                ^
one error found

Thanks again

Keith

Keith
  • 41
  • 3

3 Answers3

3

You can capture the type information with Manifests. (T, R are invariant here to keep things simple.)

import scala.reflect._
def matchFunction[T,R](f: Function1[T,R], t : T)(implicit mt : Manifest[T], mr : Manifest[R]) = {
  val result = if ((mt.erasure, mr.erasure) == (classOf[Any], classOf[Boolean]))  "any, boolean " + f(t)
  else if((mt.erasure, mr.erasure) == (classOf[Int], classOf[Int])) "int, int " + f(t)
  else "Unknown " + f(t)
  println(result)
}

scala>     matchFunction((x : Int) => x + 1, 1)
int, int 2

scala>     matchFunction((x : Any) => true, 1 : Any)
any, boolean true

scala>     matchFunction((x : Boolean) => ! x, false)
Unknown 

For Scala 2.8 one can use context bounds, removing the two implicit parameters:

import scala.reflect._
def matchFunction[T: Manifest,R : Manifest](f: Function1[T,R], t : T) = {
  val mt = implicitly[Manifest[T]]
  val mr = implicitly[Manifest[T]]
  val result = if ((mt.erasure, mr.erasure) == (classOf[Any], classOf[Boolean]))  "any, boolean " + f(t)
  else if((mt.erasure, mr.erasure) == (classOf[Int], classOf[Int])) "int, int " + f(t)
  else "Unknown " + f(t)
  println(result)
}
Thomas Jung
  • 32,428
  • 9
  • 84
  • 114
0

Have a look at this question: Pattern matching zero-argument functions in scala: mystified by warning

Community
  • 1
  • 1
Emil Ivanov
  • 37,300
  • 12
  • 75
  • 90
  • Hi I had taken a look at that. I tried the top answer. The next difficulty is that I want to call the function. If I change the code to actually call the function like below I get a compiler error. Does anybody know how I can get around this object TestTypeErasure { def doTest(parameter: Any) = { parameter match { case function:Function1[_, _] => function("Whatever") } } def main(args:Array[String]) { } } Thanks again Keith – Keith Jan 25 '10 at 15:42
0

There are a variety of approaches that might work, none of which are all that straightforward.

One option is to use manifests, but you'd have to define your own variant of match that was manifest-aware. You can read more about manifests here. If you have to do this sort of thing a lot, that would be the way to go, although this feature is still considered to be experimental.

Another option, if your usage is relatively lightweight, is to wrap the function in some class that is not generic. For example,

object Example {
  def hasString(a:Any) = (a!=null && a.toString.length>0)

  case class AnyImpliesBoolean(f: (Any) => Boolean) { } 
  implicit def callAIB(aib: AnyImpliesBoolean) = aib.f

  def callWrapped(a: Any) {
    a match {
      case aib: AnyImpliesBoolean => println( aib("Check") )
      case _ => println("(Nothing)")
    }
  }

  def tryMe() {
    val has = AnyImpliesBoolean(hasString _)
    callWrapped( has )
    callWrapped("foo")
    callWrapped((s:String)=>true)
  }
}

scala> Example.tryMe
true
(Nothing)
(Nothing)

If you are wrapping several different functions, but not too many of them, you can create a base class WrappedFunction and then have things like AnyImpliesBoolean extend WrappedFunction.

Yet another option is to not actually pass functions around, but to instead use reflection to pass java.lang.Methods around. Methods know their types. Even with some pretty Scala wrappers, it still would be a little clunky (and it's not high-performance).

(Edited to add the manifest link I was missing.)

Community
  • 1
  • 1
Rex Kerr
  • 166,841
  • 26
  • 322
  • 407