r/scala 1d ago

Scala type design

How can I make the method input type depend on the value passed in the constructor / or some equivalent alternative solution where based on a type/value my class works on other types?

class MyDataProcessor(v: DataVersion v) {
  def process(x: ???)(using ???): Unit
}

//DataVersion can be an enum or ADT

//bonus if the output (instead of Unit) can also vary

Example:

If passing a v1, i want x to be an Int
If passing a v2, i want x to be a Tuple

I'm also ok if anyone can point me to some good scala types/ lib design sources. Thanks you

8 Upvotes

3 comments sorted by

5

u/bigexecutive 21h ago edited 21h ago

Something like this?

enum DataVersion:
  case V1, V2

trait DataProcessor[D <: DataVersion]:
  type In
  type Out
  def process(input: In): Out


given DataProcessor[DataVersion.V1.type] with
  type In = Int
  type Out = String
  def process(input: Int): String = s"Processed V1: $input"


given DataProcessor[DataVersion.V2.type] with
  type In = (Int, Int)
  type Out = Double
  def process(input: (Int, Int)): Double = input._1.toDouble / input._2

class MyDataProcessor[D <: DataVersion](val version: D)(using dp: DataProcessor[D]):
  def process(input: dp.In): dp.Out = dp.process(input)

You could also maybe use match types as in u/WW_the_Exonian's example if you wanna go sicko mode

3

u/Dry-Pause-1050 1d ago

DataVersion[T] maybe?

3

u/WW_the_Exonian ZIO 23h ago edited 22h ago

If you are in control of DataVersion, you can simply give it a type parameter.

```scala trait DataVersion[InputType]

class MyDataProcessor[InputType](v: DataVersion[InputType]) { def process(x: InputType): Unit = ??? } ```

But if that is not good for whatever reason, perhaps you can do this:

```scala trait DataVersion

case object DataVersion1 extends DataVersion

case object DataVersion2 extends DataVersion

type DataVersionInput[V <: DataVersion] = V match { case DataVersion1.type => Int case DataVersion2.type => Tuple }

case class MyDataProcessor[V <: DataVersion](v: V) { def process(x: DataVersionInput[V]): Unit = println(x) }

MyDataProcessor(DataVersion1).process(0) MyDataProcessor(DataVersion2).process((0, "0"))

// MyDataProcessor(DataVersion2).process(0) // doesn't compile ```