Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a scala method with type param that cannot be Any

In below example, I want to define a contains method that doesn't compile if a and b are not of the same base type.

  • In contains1 impl, if a is Seq[Int] and b is String, T is derived to be Any, and it compiles. This is not I want.
  • In contains2 impl, if a is Seq[Int] and b is String, then it doesn't compile. The behavior is what I want.
def contains1[T](a: Seq[T], b: T): Boolean = a.contains(b)

println(contains1(Seq(1,2,3), "four")) // false

def contains2[T: Ordering](a: Seq[T], b: T): Boolean = a.contains(b)

println(contains2(Seq(1,2,3), "four")) // compilation error
// cmd7.sc:1: No implicit Ordering defined for Any.
// val res7 = isMatched(Seq(1,2,3), "s")
                    ^
// Compilation Failed

However, is there a simpler way to achieve the same behaviour as in contains2? Ordering context bound confuses me as the method has nothing to do with sorting/ordering at all.

like image 321
0xbe1 Avatar asked Jun 17 '19 18:06

0xbe1


1 Answers

You could use generalized type constraints operator =:=.

For example:

def contains[A,B](a: Seq[A], b: B)(implicit evidence: A =:= B): Boolean = a.contains(b)

and then:

println(contains1(Seq(1,2,3), "four")) //fails with Cannot prove that Int =:= String.
println(contains1(Seq("one"), "four")) //returns false
println(contains1(Seq("one", "four"), "four")) //true

More on generalized type constraints here and here.

As LuisMiguelMejíaSuárez noticed, you could also consider using B <:< A instead of A =:= B. I won't elaborate on differences between these two because it's described in linked answer and article, but in brief, <:< would also allow all B that are a subtype of A, while =:= needs types to match exactly.

like image 67
Krzysztof Atłasik Avatar answered Nov 01 '22 13:11

Krzysztof Atłasik