I have the following pattern matching case in a scala function:
def someFunction(sequences: Iterable[Seq[Int]]):Seq[Int] = sequences match{
case Seq() => Seq(1)
case _ => ...
...
}
And I get the following warning:
warning: non variable type-argument A in type pattern Seq[A] is unchecked since it is eliminated by erasure
case Seq(_) => Seq(1)
^
one warning found
What does this mean?
This warning is a bit spurious, and will not be present on Scala 2.10. In fact, I think it's a regression from Scala 2.8 (that is, it is not present there).
The reason for the warning is that it interprets Seq(_) to mean Seq(_: Seq[Int]), since that's the type parameter of sequences, and then complaining that it can't guarantee that Int there, since, at compile time, that will be erased. As I said, it's spurious.
Related
I've started learning Scala.
I was surprised that next code compiles:
object Hello extends App {
def isOne(num: Int) = num match {
case 1 => "hello"
}
}
You can't do something similar in Rust for example.
Why Scala compiler does not force me to provide default value for case ?
I'd say that it is a little bit unsafe.
Is there any scala linter or something else? Maybe some flags?
Since Scala 2.13.4 there were improvement to exhaustivity checking of unsealed types such as Int so try with compiler flag
-Xlint:strict-unsealed-patmat
for example
scala -Xlint:strict-unsealed-patmat -Xfatal-warnings
Welcome to Scala 2.13.5 (OpenJDK 64-Bit Server VM, Java 1.8.0_275).
Type in expressions for evaluation. Or try :help.
scala> def isOne(num: Int) = num match {
| case 1 => "hello"
| }
^
warning: match may not be exhaustive.
It would fail on the following input: (x: Int forSome x not in 1)
error: No warnings can be incurred under -Werror.
In general though, according to Pattern Matching Expressions
If the selector of a pattern match is an instance of a sealed class,
the compilation of pattern matching can emit warnings which diagnose
that a given set of patterns is not exhaustive, i.e. that there is a
possibility of a MatchError being raised at run-time.
Well you can deal with it a bit on structural matching, by setting
"-Xfatal-warnings" option in scalac settings, this will lift this and other warnings to errors.
So the scala compiler is complaining that a pattern match might not be exhaustive for the method foo and I wonder why. This is the code:
abstract class Foo {
def foo(that: Foo): Unit = (this, that) match {
case (Foo_1(), Foo_1()) => //case 1
case (Foo_1(), Foo_2()) => //case 2
case (Foo_2(), Foo_1()) => //case 3
case (Foo_2(), Foo_2()) => //case 4
// Compiler warning
}
def fooThis(): Unit = this match {
case Foo_1() => //do something
case Foo_2() => //do something
// Works fine
}
def fooThat(that: Foo): Unit = that match {
case Foo_1() => //do something
case Foo_2() => //do something
// Works fine
}
}
case class Foo_1() extends Foo
case class Foo_2() extends Foo
And this is the error:
Warning:(5, 32) match may not be exhaustive.
It would fail on the following inputs: (Foo(), _), (Foo_1(), _), (Foo_2(), _), (_, Foo()), (_, Foo_1()), (_, Foo_2()), (_, _)
def foo(that: Foo): Unit = (this, that) match {
Since this and that are of type Foo, and Foo can only be of type Foo_1 or Foo_2, the cases in foo are all possible combinations.
I added fooThis and fooThat for sake of completeness and to show that matching Foo_1 and Foo_2 suffices. The compiler message suggests that there are other types that can be matched (i.e. Foo and _).
So why is this warning shown?
Related:
Scala bug: fixed in 2.12.0-M4. My scala welcome message:
Welcome to Scala 2.12.1 (Java HotSpot(TM) Client VM, Java 1.8.0_131).
Scala bug: false match not exhaustive warning on (unsealed, sealed) tuple
EDIT
The compiler seems to complain as soon as you use tuples. If we add a dummy variable to fooThis as follows
def fooThis(): Unit = (this, Foo_1()) match {
case (Foo_1(),_) => //do something
case (Foo_2(),_) => //do something
}
we get the following compiler warning
Warning:(13, 27) match may not be exhaustive.
It would fail on the following input: (_, _)
def fooThis(): Unit = (this, Foo_1()) match {
The Scala compiler won't give exhaustive match warnings for non-sealed traits (like your Foo). This explains why fooThis and fooThat compile without warnings.
If you want warnings here (and you should, because they're better than MatchError exceptions at runtime) you have a couple of options:
Make Foo sealed. This creates an ADT, which is safe to pattern match against in the sense that you'll get exhaustivity warnings when you forget a case. Option is an ADT that you're probably familiar with from the standard library. Here, you've already got cases for both Foo_1 and Foo_2, so you won't get an exhaustivity warning. But if you ever forget either case, you will. You probably want to make Foo_1 and Foo_2 final while you're at it.
Leave Foo unsealed, use Typelevel Scala and enable its -Xlint:strict-unsealed-patmat warnings.
On the other hand, the Scala compiler will give exhaustive match warnings for final case classes like Tuple2, which is what you're matching against in your foo method.
To answer "why is the warning shown?", consider what happens if we do this:
case class Foo3() extends Foo
val foo3 = Foo3()
foo3.foo(foo3)
(Answer: it throws a MatchError at runtime.)
The warning is the Scala compiler's way of helping you avoid the exception at runtime. If you want to make the warning go away, you could:
Make Foo sealed (again, creating an ADT), preventing Foo3 from sneaking in elsewhere.
Add a wildcard case _ => ....
Make the match unchecked: ((this, that): #unchecked) match { ....
Don't do number 3, because it leaves you vulnerable to MatchErrors at runtime when someone introduces Foo3.
So, perhaps the question isn't really "why does the match in foo generate a warning", but "why doesn't the match in fooThis and fooThat generate a warning".
It seems making the abstract class sealed at least makes the compiler warning go away:
sealed abstract class Foo {
Though I'm not too sure why. It might be related to: https://issues.scala-lang.org/browse/SI-9351
Figuring out all subclasses of a class is called Class Hierarchy Analysis, and doing static CHA in a language with dynamic code loading is equivalent to solving the Halting Problem.
Plus, one of the goals of Scala is separate compilation and deployment of independent modules, so the compiler simply cannot know whether or not a class is subclassed in another module, because it never looks at more than one module. (After all, you could compile a module against the interface of some other module without that module even existing on your system!) That's why sealed requires all subclasses to be defined in the same compilation unit.
That's why the compiler doesn't show warnings, because its aware of the existing subclasses.
I want to map over a Map that has the type List[~(A,Option[B])] but before I map over it I group it by A. Now that I can map over it, I have to match the Tuple of the Map:
val rawData: List[A ~ Option[B]]
rawData
.groupBy(_._1)
.map(case (first: A, second: Seq[A ~ Option[B]]) =>
C(first, second.map(_._2))
)
Now the Compiler warns me:
non-variable type argument anorm.~[A,Option[B]] in type pattern Seq[anorm.~[A,Option[B]]] is unchecked since it is eliminated by erasure
I found several solutions to make that matching possible, but I have the feeling, that it could be also possible to avoid the matching at all as I only want to go through that Map that has already a defined Type. How could this be possible?
In this case you actually don't have to worry about this. The error is because your case statement is too verbose. Change to the following:
rawData.groupBy(_._1).map(case (first, second) =>
C(first, second.map(_._2))
)
The types in the case statement restrict the type of the tuple (which is unnecessary). However, they restrict it in a way which is not verifiable at runtime (due to type erasure), that's why you get the error.
In Scala 2.10.0-M4
object X
def f(e: Either[Int, X.type]) = e match {
case Left(i) => i
case Right(X) => 0
}
gives:
warning: match may not be exhaustive.
It would fail on the following input: Right(<not X>)
Is this correct? Surely the match is in fact exhaustive.
(Meanwhile, back in Scala 2.9.X we get
error: pattern type is incompatible with expected type;
found : object X
required: X.type
case Right(X) => 0
which presumably was a bug.)
Sadly, there are two values which inhabit X.type. One is the obvious one, X, and the other of course is null. Thus your pattern has missed a case :(
And it's been patched, c.f. https://github.com/retronym/scala/compare/ticket/5968.
I'm trying to understand what Scala does with Case Classes that makes them somehow immune to type erasure warnings.
Let's say we have the following, simple class structure. It's basically an Either:
abstract class BlackOrWhite[A, B]
case class Black[A,B]( val left: A ) extends BlackOrWhite[A,B]
case class White[A,B]( val right: B ) extends BlackOrWhite[A,B]
And you're trying to use it like this:
object Main extends App {
def echo[A,B] ( input: BlackOrWhite[A,B] ) = input match {
case Black(left) => println( "Black: " + left )
case White(right) => println( "White: " + right )
}
echo( Black[String, Int]( "String!" ) )
echo( White[String, Int]( 1234 ) )
}
Everything compiles and runs without any problems. However, when I try implementing the unapply method myself, the compiler throws a warning. I used the following class structure with the same Main class above:
abstract class BlackOrWhite[A, B]
case class Black[A,B]( val left: A ) extends BlackOrWhite[A,B]
object White {
def apply[A,B]( right: B ): White[A,B] = new White[A,B](right)
def unapply[B]( value: White[_,B] ): Option[B] = Some( value.right )
}
class White[A,B]( val right: B ) extends BlackOrWhite[A,B]
Compiling that with the -unchecked flag issues the following warning:
[info] Compiling 1 Scala source to target/scala-2.9.1.final/classes...
[warn] src/main/scala/Test.scala:41: non variable type-argument B in type pattern main.scala.White[_, B] is unchecked since it is eliminated by erasure
[warn] case White(right) => println( "White: " + right )
[warn] ^
[warn] one warning found
[info] Running main.scala.Main
Now, I understand type erasure and I've tried to get around the warning with Manifests (to no avail so far), but what is the difference between the two implementations? Are case classes doing something that I need to add in? Can this be circumvented with Manifests?
I even tried running the case class implementation through the scala compiler with the -Xprint:typer flag turned on, but the unapply method looks pretty much like I expected:
case <synthetic> def unapply[A >: Nothing <: Any, B >: Nothing <: Any](x$0: $iw.$iw.White[A,B]): Option[B] = if (x$0.==(null))
scala.this.None
else
scala.Some.apply[B](x$0.right);
I cannot give a complete answer, but I can tell you that even though the compiler generates an unapply method for case classes, when it pattern matches on a case class it does not use that unapply method. If you try -Ybrowse:typer using both builtin case matching and your unapply method, you will see a very different syntax tree is produced (for the match) depending on which is used. You can also browse the later phases and see that the difference remains.
Why Scala does not use the builtin unapply I am not sure, though it may be for the reason you bring up. And how to get around it for your own unapply I have no idea. But this is the reason Scala seems to magically avoid the problem.
After experimenting, apparently this version of unapply works, though I'm a bit confused about why:
def unapply[A,B](value: BlackOrWhite[A,B]): Option[B] = value match {
case w: White[_,_] => Some(w.right)
case _ => None
}
The difficulty with your unapply is that somehow the compiler has to be convinced that if a White[A,B] extends a BlackOrWhite[C,D] then B is the same as D, which apparently the compiler is able to figure out in this version but not in yours. Not sure why.
I can't give you the answer on the difference between case class match and unapply. However in their book (Odersky, Spoon, Venners) "Programming in Scala" 2nd chptr 26.6 "Extractors versus case classes" they write:
"they (case classes) usually lead to more efficient pattern matches
than extractors, because the Scala compiler can optimize patterns over
case classes much better than patterns over extractors. This is
because the mechanisms of case classes are fixed, whereas an unapply
or unapplySeq method in an extractor could do almost anything. Third,
if your case classes inherit from a sealed base class, the Scala
compiler will check our pattern matches for exhaustiveness and will
complain if some combination of possible values is not covered by a
pattern. No such exhaustiveness checks are available for extractors."
Which says to me that the two are more different than one would expect at first glance, however without being specific on what the exact differences are.