Let's says that I have an ADT that look like that
sealed trait TT
case class A(...) extends TT
case class B(...) extends TT
case class C(...) extends TT
// ... lot of others
And I have this function that return true for of subset of TT
. Let's say A
and C
.
def shouldIPublish(tt: TT): Boolean = ???
tt
we receive comes from a SortedSet
that I can't really change. Here is how the function shouldIPublish
is called : tts.exists(shouldIPublish)
( tts
is a SortedSet[TT]
). It is erased.TT
type. If the actual type of tt
is in a subset (ie A
or C
) return true
otherwise false
.val shouldIPublishPF: PartialFunction[TT, Unit] = {
case _: A =>
case _: C =>
}
def shouldIPublish(tt: TT): Boolean = shouldIPublishPF.isDefinedAt(tt)
I use partial functions here because the actual problem is a bit more complex. I use orElse
to combine several partial functions together.
This solution is easy to reason about and simple enough. But,
A
and C
. My unit test should fail when a new type is added to the partial function.Maybe the simplest solution. I could have a Set
and get class with .getClass
. It seems ugly though.
Set(A.getClass, C.getClass)
Looked quite promising at first. Very idiomatic.
type ShoudIPublish = A :+: C :+: CNil
Unfortunately, I don't see how to test that a type is "contained" in ShoudIPublish
. And I don't know if we can collect the list of all types (here A
and C
).
Do you have any suggestion?
Type class looks like a solution (if you know the type of tt
ie specific subtype of TT
at compile time)
trait ShouldIPublish[T <: TT]
object ShouldIPublish {
implicit val a: ShouldIPublish[A] = null
implicit val c: ShouldIPublish[C] = null
}
def shouldIPublish[T <: TT : ShouldIPublish](tt: T) = ???
shouldIPublish(A())
// shouldIPublish(B()) // doesn't compile
shouldIPublish(C())
Standard type class is shapeless.ops.coproduct.Inject
type ShoudIPublish = A :+: C :+: CNil
def shouldIPublish[T <: TT : Inject[ShoudIPublish, *]](tt: T) = ???
shouldIPublish(A())
// shouldIPublish(B()) // doesn't compile
shouldIPublish(C())
OOP-style solution would be to use a trait (if you can modify the hierarchy)
trait ShouldIPublish
sealed trait TT
case class A() extends TT with ShouldIPublish
case class B() extends TT
case class C() extends TT with ShouldIPublish
def shouldIPublish[T <: TT with ShouldIPublish](tt: T) = ???
shouldIPublish(A())
// shouldIPublish(B()) // doesn't compile
shouldIPublish(C())
Pattern-matching solution can work at runtime when you don't know specific subtype of TT
at compile time
def shouldIPublish(tt: TT) = tt match {
case _: A => println("A")
case _: C => println("C")
}
shouldIPublish(A(): TT)// A
shouldIPublish(B(): TT)// MatchError
shouldIPublish(C(): TT)// C
or
trait ShouldIPublish
sealed trait TT
case class A() extends TT with ShouldIPublish
case class B() extends TT
case class C() extends TT with ShouldIPublish
def shouldIPublish(tt: TT) = tt match {
case _: ShouldIPublish => println("A or C")
}
shouldIPublish(A(): TT)// A or C
shouldIPublish(B(): TT)// MatchError
shouldIPublish(C(): TT)// A or C
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.