containsSlice
is just a call to indexOfSlice
, which has the following signature:
indexOfSlice[B >: A](that: GenSeq[B]): Int
containsSlice
could do the same thing.
It's useful to constrain the type param with a lower bound so you can do this:
apm@mara:~/tmp$ scalam -Ywarn-infer-any
Welcome to Scala version 2.11.0-M7 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> "abcdef" contains 8
<console>:8: warning: a type was inferred to be `AnyVal`; this may indicate a programming error.
"abcdef" contains 8
^
res0: Boolean = false
The warning tells you that type safety has been compromised.
-Xlint
includes -Ywarn-infer-any
.
But check this out:
scala> "abcdef" indexOfSlice (1 to 10)
res1: Int = -1
No warning?
You can turn on the fancy new -Ytyper-debug
to see:
| | | | | \-> [B >: Char](that: scala.collection.GenSeq[B], from: Int)Int <and> [B >: Char](that: scala.collection.GenSeq[B])Int
| | | | solving for (B: ?B)
and
| | | | solving for (B: ?B)
| | | | \-> Int
which seems to mean that in the presence of overloading, you don't get the warning.
That's because of how typechecking is done for overloading.
-Xprint:typer
confirms that, of course, you wind up with AnyVal
, but it must happen later:
private[this] val res0: Int = scala.this.Predef.augmentString("abcdef").indexOfSlice[AnyVal](scala.this.Predef.intWrapper(1).to(10));
We didn't really need another reason that overloading is evil, but did you know that println
is also evil?
scala> println("abcdef" contains 8)
false
No warning.
It turns out that the warning is very conservative:
// Can warn about inferring Any/AnyVal as long as they don't appear
// explicitly anywhere amongst the formal, argument, result, or expected type.
Since println
takes Any
, that is our expected type for the expression, and we lose the warning.
In summary,
import reflect.runtime._
import universe._
case class Foo[+A](a: A) {
def f[B >: A : TypeTag](other: Foo[B]): String = typeTag[B].toString
def g[B] = "huh"
def j[B >: A : TypeTag](other: Foo[B]): String = typeTag[B].toString
def j[B >: A : TypeTag](other: Foo[B], dummy: Int): String = typeTag[B].toString
}
object Test extends App {
val x = Foo("abc") f Foo(3) // warn
val y = Foo("abc").g
val w = Foo("abc") j Foo(3) // nowarn
val z = Foo("abc") j (Foo(3), 0)
Console println s"$x $y $w $z"
val b = "abcdef" contains 8 // warn
println("abcdef" contains 8) // nowarn
implicit class Sectional[+A](val as: Seq[A]) {
def containsSection[B >: A](other: Seq[B]): Boolean = as containsSlice other
}
("abcdefg": Seq[Char]) containsSection (1 to 10) // warn
implicit class Sectional2(val as: String) {
def containsSection[B >: String](other: Seq[B]): Boolean = as containsSlice other
}
"abcdefg" containsSection (1 to 10) // warn
}
Too bad about special-casing String.