Reputation: 19
I would like to limit parameter function to have parameter only case class with limited field types. Let's say i would allow only Int
and String
def apply[T <: ???](t: T) {
...
}
case class OneParam(int: Int)
case class TwoParams(int: Int, str: String)
case class CompilationErrorClass(list: Array[String])
val oneParam = OneParam(1)
val twoParams = TwoParams(1, "2")
val compilationErrorClass = CompilationErrorClass(List())
val result1 = apply[OneParam](oneParam)
val result2 = apply[TwoParams](twoParams)
val result3 = apply[CompilationErrorClass](compilationErrorClass) // -- this will not compile as has not allowed upper-bound parameter type
How this trick can be done in scala?
Upvotes: 0
Views: 109
Reputation: 1551
Here we go (scala3):
import scala.deriving.Mirror.ProductOf
type AllowTypes = Int *: EmptyTuple | String *: EmptyTuple | (Int, String) | (String, Int)
def size[P <: Product](t: P)
(using p: ProductOf[P],
ev: p.MirroredElemTypes <:< AllowTypes): Int =
Tuple.fromProductTyped(t).size
scala> size(OneParam(0))
val res0: Int = 1
scala> size(TwoParams(1, ""))
val res1: Int = 2
scala> size(CompilationErrorClass(Array()))
-- Error: --------------------------------------------------------------------------------------------------------------------------------------------------
1 |size(CompilationErrorClass(Array()))
| ^
| Cannot prove that p.MirroredElemTypes <:< AllowTypes.
1 error found
Or even general solution, allow all case classes with arbitrarily int or string arguments:
scala> type Allowed[T <: Tuple] = T match
| case EmptyTuple => DummyImplicit
| case (Int | String) *: t => Allowed[t]
|
scala> import scala.deriving.Mirror.ProductOf
|
| def size[P <: Product](t: P)
| (using p: ProductOf[P],
| ev: Allowed[p.MirroredElemTypes]): Int =
| Tuple.fromProductTyped(t).size
|
def size[P <: Product](t: P)(using p: deriving.Mirror.ProductOf[P], ev: Allowed[p.MirroredElemTypes]): Int
scala> case class A(i: Int, j: Int, x: String, y: String)
// defined case class A
scala> case class X(x1: Int, x2: String, x3: Int, x4: String, x5: String)
// defined case class X
scala> case class Y(l: Long)
// defined case class Y
scala> size(A(0, 1, "", ""))
val res0: Int = 4
scala> size(X(0, "", 1, "", ""))
val res1: Int = 5
scala> size(Y(0))
-- Error: --------------------------------------------------------------------------------------------------------------------------------------------------
1 |size(Y(0))
| ^
| Match type reduction failed since selector Long *: EmptyTuple.type
| matches none of the cases
|
| case EmptyTuple => DummyImplicit
| case (Int | String) *: t => Allowed[t]
1 error found
Upvotes: 1