jeudi 23 avril 2020

Generic return type in Scala structural type method

I'm trying to create a structural type in Scala with a method that has a generic return type. For instance, something like:

type Manipulable[T] = Any {
  def +(x: Int): T
}

def add[T <: Manipulable[T]](o: T, x: Int) = o + x

// these lines throw Exceptions
add(19.0, 3)
add(3, 3)
add(42L, 3)

Scala's structural types are set scoped to AnyRef by default, so to use the value types (Java's primitives), we prepend the Any before the type definition. Structural types can take type parameters, as seen above, but those type parameters cannot then be used as the types of any method value parameters. (You could have x: => T, but not x: T.)

When trying to use add() on a Manipulable[Double] or Manipulable[Int] (etc.), though, we get a Java NoSuchMethodException. Note that this only happens with methods with purely generic return types. The following structural type, for instance, works fine:

type Manipulable[T] = Any {
  def getClass (): Class[T] // Class[_] also works
  def toString() : String
}

def gc[T <: Manipulable[T]](o: T): Class[T] = o.getClass()

gc(19.0) // Class[Double] = class java.lang.Double
gc(3)    // Class[Int] = class java.lang.Integer
gc(42L)  // Class[Long] = class java.lang.Long

def str[T <: Manipulable[T]](o: T): String = o.toString()

str(19.0) // String = 19.0
str(3)    // String = 3
str(42L)  // String = 42

I'm guessing this is an issue with value types in Scala, because reference types seem fine:

type Manipulable[T] = Any {
  def substring(x: Int) : T
}

def ss[T <: Manipulable[T]](o: T, x: Int) = o.substring(x)

ss("hello, world", 7) // prints "world"

Any ideas?





Aucun commentaire:

Enregistrer un commentaire