Reputation: 6006
Having following structure:
trait ParentType
trait ChildType extends ParentType
case class FooBar[+T <: ParentType](s: String, data: T)
object FooBar {
def apply[T <: ChildType](i: Int, data: T): FooBar[T] = new FooBar(s"$i", data)
}
case class Foo(a: Int) extends ParentType
case class Bar(s: String) extends ChildType
def function1[T <: ParentType](obj: FooBar[T]): Unit = ()
def function2[T <: ChildType](obj: FooBar[T]): Unit = ()
Is possible(and in what way) to change the signature(with generics declaration) of function1
and function2
such that function1
can only except parameters of FooBar
with type T
that is direct descendant of ParentType
(and prohibit any T
that is direct descendant of ChildType
) and function2
in another way around - except only parameters with T
that are direct descendants of ChildType
and prohibit all ParentType
T
's
In other words this shouldn't compile
function1(FooBar("a", Bar("1"))) //because Bar is not direct descendant of ParentType
Upvotes: 0
Views: 92
Reputation: 6006
With help of @LuisMiguelMejíaSuárez (see his comments to the question) I managed to achieve what I wanted. So, taking into account as well that I need context bound for Arbitrary
from scalacheck to be in these functions declarations, Luis suggestion to use shapless(in particular I found out that <:!<
can solve my problem) helped
import shapless._
def function1[T <: ParentType](obj: FooBar[T])(implicit: arb: Arbitrary[T], ev: T <:!< ChildType): Unit = ()
def function2[T <: ChildType : Arbitrary](obj: FooBar[T]): Unit = ()
Unfortunately I didn't manage to achieve the override of function1
(just with different ev
types), but having those functions with different names I can reuse function1
from function2
(I need just to call function1
with explicit parameter for <:!<
instance which is shapeless.nsub
).
So with this solution any ChildType
instance can't be applied to function1
(at least as is) because such application results in
ambiguous implicit values:
both method nsubAmbig1 in package shapeless of type [A, B >: A]A <:!< B
and method nsubAmbig2 in package shapeless of type [A, B >: A]A <:!< B
match expected type Bar <:!< ChildType
I guess this is what was designed behind usage of <:!<
type(but if explicitly to specify an instance of <:!<
it will work)
Here is a link to scastie worksheet to try out the problem
Upvotes: 0
Reputation: 40510
The question does not make very much sense, I am afraid, but to answer what you wrote in comments:
I want function2 to accept "containers" FooBars of Mammals only
So, it should be def function2(m: Foobar[Mammal])
and function1 - all other group types of animals(but not mammals)
This is a weird requirement. If you are sure you need this (I really, really doubt you actually do), I suggest something like this:
trait NotMammal extends Animal
class Fish extends NotMammal
class Reptile extends NotMammal
...
def funcction1(n: Foobar[NotMammal]) = ???
Upvotes: 1