I have a sealed trait and some case classes that extend that trait, like so:
sealed trait Foo
case class Bar extends Foo
case class Baz extends Foo
In a different part of my code, I have a trait with a method on it that operates on Foo
s
trait Example {
def method(arg1: Foo, arg2: Foo)
}
However, I would really like to ensure that arg1
and arg2
always have the same type; that is, they should both be either Bar
or Baz
, and never a mix. My first intuition is to use generics:
trait Example {
def method[T: Foo](arg1: T, arg2: T)
}
But I run into two problems:
T
needs to be present on Example
as far as I can tell. Can I make method
generic without "infecting" the rest of the trait?Actually if you want
to ensure that
arg1
andarg2
always have the same type; that is, they should both be eitherBar
orBaz
, and never a mix
then
trait Example {
def method[T <: Foo](arg1: T, arg2: T) = ???
}
is incorrect. new Example {}.method(Bar(), Baz())
compiles because T
is inferred to be Foo
.
Correct is
trait Example {
def method[T <: Foo, U <: Foo](arg1: T, arg2: U)(implicit ev: T =:= U) = ???
}
Then new Example {}.method(Bar(), Baz())
doesn't compile but new Example {}.method(Bar(), Bar())
and new Example {}.method(Baz(), Baz())
compile.
More details when generalized type constraints ( <:<
, =:=
and even <:!<
, =:!=
) should be preferred over type bounds ( <:
, >:
) can be found here:
https://blog.bruchez.name/2015/11/generalized-type-constraints-in-scala.html (See example
def tupleIfSubtype[T <: U, U](t: T, u: U) = (t, u)
vs.
def tupleIfSubtype[T, U](t: T, u: U)(implicit ev: T <:< U) = (t, u)
there.)
https://apiumhub.com/tech-blog-barcelona/scala-generics-generalized-type-constraints/ ( https://dzone.com/articles/scala-generics-generalized-type-constraints-part-3 )
https://herringtondarkholme.github.io/2014/09/30/scala-operator/
You need to specify <:
:
stands for context bound and works in combination with a type class like trait Zoo[T]
<:
stands for upper type bound
trait Example {
def method[T <: Foo](arg1: T, arg2: T)
}
Update:
As @Dmytro Mitin correctly pointed out, the correct solution requires evidence check =:=
to be performed.
def method[T <: Foo, U <: Foo](arg1: T, arg2: U)(implicit ev: T =:= U)
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.