开发者

How can I match a function signature without getting type erasure compiler warnings in Scala

开发者 https://www.devze.com 2022-12-17 06:37 出处:网络
Can anyone re-write this code to do the same thing but without any compiler warnings please:- object TestTypeErasure {

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

object TestTypeErasure {

  开发者_如何学JAVAdef 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


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)
}


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


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.)

0

精彩评论

暂无评论...
验证码 换一张
取 消