2

In Scala, I am doing some Java interop. I am creating a value of class Sample.Individual and I am calling a static Java method like Sample.Individual.newBuilder(). I am using a few classes that all have this same static method (eg: Sample.Position and Sample.Feature). I want to make a function that parameterizes over them, so something like:

def p[T](s: String): T = {
    val pb = T.newBuilder() // this returns a value of type T.Builder
    ... do stuff with pb ...
    pb.build() // this returns a value of type T
}

but this tells me "not found: value T"

What is the right way to parameterize the type Sample.Individual that lets me also call static methods contained in it from Scala?

prismofeverything
  • 8,799
  • 8
  • 38
  • 53
  • Scala *might* have sugar for this, but it would require runtime reflection to actually implement, since it couldn't use the normal dynamic dispatch. – chrylis -cautiouslyoptimistic- May 12 '16 at 00:07
  • 1
    I don't think there is a direct way to do that. At least not as you demonstrated. But you can use [`TypeTags/ClassTags`](http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html) to get more information about the type being handled and then use [Java Reflections API](https://docs.oracle.com/javase/tutorial/reflect/) to [invoke the static method](http://stackoverflow.com/questions/2467544/invoking-a-static-method-using-reflection). – marcospereira May 12 '16 at 00:55

1 Answers1

1

I'd strongly recommend you don't go forward with this idea. Even if you find a way to do it, it's not idiomatic Scala. It's remotely possible you shave off a few lines of code, but you loose in readability and performance; bad trade-off.

The problem you're having is that you're giving your p function a type parameter T, and then invoking the newBuilder method on that type T. You can't do that, because Scala knows nothing about your type T.

Instead, first learn a little more about those Java types. Do all the potentially constructed classes extend a common type? If not, you're out of luck (you're technically not out of luck if you choose to pimp the library you're using, but please don't :P).

Otherwise, just import those types (including the generic one). Put the generic type as the type of your p function and match on the string, then just instantiate your type. Strings can be whatever, so you probably want to return an Option[GenericClass] rather than a GenericClass.

e.g.

import xxx.GenericClassBuilder
import xxx.GenericClass
import xxx.ClassA
import xxx.ClassB

def p(s: String): Option[GenericClass] = {
   val maybePb: Option[GenericClassBuilder] = s match {
      case "ClassA" => Some(ClassA.newBuilder())
      case "ClassB" => Some(ClassB.newBuilder())
      case _ => None
   }
   maybePb.foreach { pb => ... do side-effecty stuff with pb ...}
   maybePb.map(_.build())
}
mlg
  • 1,447
  • 15
  • 19