0

I'm trying to figure out a mechanism to implement something like the following in Java. Essentially, I'd like to use the argument to a generic class as a generic class:

class A<T> {
  T<String> aString;
}

Is this, or something equivalent, where I can pass arguments to the type constructor received as arguments, possible at all in Java? Is it possible to indicate that T has type * -> * or that it is some sort of type constructor? If not, how about a different language?

Ivan Perez
  • 582
  • 2
  • 17
  • 1
    Don't know about scala, but Java does not have this. Perhaps this is an [XY problem](https://xyproblem.info/). What problem are you trying to solve exactly? – Sweeper May 04 '23 at 05:49
  • I'm literally just trying to build what I have there. I want to be able to "wrap" all members of a class in an argument generic (or type constructor) so that I can decide the behavior when I instantiate it. For example, an `A` would contain a vector of strings, an `A` would contain a hash map of strings, and so on. If I have two private members (e.g., a `String` and an `Integer`), and I wrap both with `T<>`, then `A` would have both a `HashMap` and a `HashMap`, and so on. – Ivan Perez May 04 '23 at 05:54
  • 2
    Have a look at this for Scala https://www.baeldung.com/scala/higher-kinded-types – Tim Moore May 04 '23 at 06:28

2 Answers2

2

I don't know about Java (but this question is probably relevant for you), but you can do this in Scala

final case class A[T[_], B](a: T[B])

And then you can instantiate classes like so, relying on type inference:

val a1 = A(List("hello", "world"))
val a2 = A(Some(42))

You can play around with this code here on Scastie.

stefanobaghino
  • 11,253
  • 4
  • 35
  • 63
0

This is called a higher-kinded type. Here's an example in Scala of exactly what you want (Scastie):

import scala.collection.mutable.HashMap
trait A[T[_]] {
  def aString: T[String]
}

class AVector extends A[Vector] {
  def aString: Vector[String] = Vector("Hello, world!")
}

type StringKeyedHashMap[T] = HashMap[String, T]
class AHashMap[T] extends A[StringKeyedHashMap] {
  def aString: HashMap[String, String] = HashMap(
    "Hello, world!" -> "Goodbye, world!"
  )
}


println((new AVector).aString)  // Vector(Hello, world!)
println((new AHashMap).aString) // HashMap(Hello, world! -> Goodbye, world!)

Note that in the HashMap example, it isn't possible to use extends A[HashMap], because HashMap requires two type parameters, and A[T[_]] only accepts types that take a single parameter. To work around this, a type alias is declared that takes one type parameter for the map values, and hardcodes the key type as String.

Tim Moore
  • 8,958
  • 2
  • 23
  • 34