Alexandru Nedelcu recently wrote Fatal Warnings and Linting in Scala, where amongst other things, I learned about the new @nowarn annotation in Scala 2.13, which allows you to selectively disable compiler warnings.

Of course, you be shouldn’t be locally suppressing compiler warnings very often. Why might you do this?

In my case, I’m writing exercises for our upcoming “Essential Effects” course (sorry, I couldn’t resist the plug!). When writing exercises, you want to provide a good code skeleton, so the student can concentrate on the essential details of the problem. I usually mark the the sections the student needs to implement with the ??? method. For example:

import cats.effect._

object HelloWorld extends IOApp {
def run(args: List[String]): IO[ExitCode] =
helloWorld.as(ExitCode.Success)

val helloWorld: IO[Unit] = ??? // TODO: print "Hello World" to the console
}

Our friend the compiler helpfully reminds us dead code following this construct regarding the line with the ???.

But I don’t want my students to have these warnings, because they become errors, because I’ve also enabled -Xfatal-warnings, which turns all compiler warnings into errors. Alex’s article goes into more detail about why you should also enable -Xfatal-warnings.

So it’s a bit of a conundrum: we don’t want warnings, because they are probably errors, but we now have errors–due to warnings–that we don’t want to bother the student with.

The @nowarn annotation let’s us locally suppress the warning:

import cats.effect._

object HelloWorld extends IOApp {
def run(args: List[String]): IO[ExitCode] =
helloWorld.as(ExitCode.Success)

@annotation.nowarn
val helloWorld: IO[Unit] = ??? // TODO: print "Hello World" to the console
}

But what if our diligent student completes the exercise? Now there aren’t actually any compiler warnings, but the code is marked with @nowarn. In my mind, the programmer should be notified of this, but unfortunately, there is no warning about this condition by default! We wouldn’t want any future revisions of this code, which might introduce warnings, to not have those warnings surfaced.

import cats.effect._

object HelloWorld extends IOApp {
def run(args: List[String]): IO[ExitCode] =
helloWorld.as(ExitCode.Success)

@annotation.nowarn // There's no warning being suppressed!
val helloWorld: IO[Unit] = IO(println("Hello World"))
}

To avoid this situation, you need to enable the -Wunused:nowarn compiler flag. Once added, if there exist any @nowarn annotations, but no warnings were actually suppressed, you’ll see this warning from the compiler: @nowarn annotation does not suppress any warnings. Now the programmer can remove the annotation. Huzzah!

In summary, if you’re on Scala 2.13 and are using @nowarn, please enable the -Wunused:nowarn compiler flag!