Here is a list of built-in warts under the org.wartremover.warts package.

ArrayEquals

Unlike other collections == on arrays and iterators checks reference equality:

List(1) == List(1) //true
Array(1) == Array(1) //false, won't compile: == is disabled, use sameElements instead

Any

Any is the top type; it is the supertype of every other type. The Scala compiler loves to infer Any as a generic type, but that is almost always incorrect. Explicit type arguments should be used instead.

// Won't compile: Inferred type containing Any
val any = List(1, true, "three")

AnyVal

See Any.

// Won't compile: Inferred type containing AnyVal
val xs = List(1, true)

AsInstanceOf

asInstanceOf is unsafe in isolation and violates parametricity when guarded by isInstanceOf. Refactor so that the desired type is proven statically.

// Won't compile: asInstanceOf is disabled
x.asInstanceOf[String]

DefaultArguments

Scala allows methods to have default arguments, which make it hard to use methods as functions.

// Won't compile: Function has default arguments
def x(y: Int = 0)

EitherProjectionPartial

scala.util.Either.LeftProjection and scala.util.Either.RightProjection have a get method which will throw if the value doesn’t match the projection. The program should be refactored to use scala.util.Either.LeftProjection#toOption and scala.util.Either.RightProjection#toOption to explicitly handle both the Some and None cases.

Enumeration

Scala’s Enumeration can cause performance problems due to its reliance on reflection. Additionally, the lack of exhaustive match checks and partial methods can lead to runtime errors. Instead of Enumeration, a sealed abstract class extended by case objects should be used instead.

Equals

Scala’s Any type provides an == method which is not type-safe. Using this method allows obviously incorrect code like 5 == "5" to compile. A better version which forbids equality checks across types (which always fail) is easily defined:

@SuppressWarnings(Array("org.wartremover.warts.Equals"))
implicit final class AnyOps[A](self: A) {
   def ===(other: A): Boolean = self == other
}

equals, eq, ne are disabled as well.

ExplicitImplicitTypes

Scala has trouble correctly resolving implicits when some of them lack explicit result types. To avoid this, all implicits should have explicit type ascriptions.

FinalCaseClass

Scala’s case classes provide a useful implementation of logicless data types. Extending a case class can break this functionality in surprising ways. This can be avoided by always making them final or sealed.

// Won't compile: case classes must be final
case class Foo()

FinalVal

Value of a final val is inlined and can cause inconsistency during incremental compilation (see sbt/sbt/issues/1543 ).

file 1:
object c {
  // Won't compile: final val is disabled
  final val v = 1
}

file 2:
println(c.v)

ImplicitConversion

Implicit conversions weaken type safety and always can be replaced by explicit conversions.

// Won't compile: implicit conversion is disabled
implicit def int2Array(i: Int) = Array.fill(i)("madness")

ImplicitParameter

Implicit parameters as configuration often lead to confusing interfaces and can result in surprising inconsistencies.

// Won't compile: Implicit parameters are disabled
def f()(implicit s: String) = ()

// Still compiles
def f[A: Ordering](a: A, other: A) = ...
def f(a: A, other: A)(implicit ordering: Ordering[A]) = ...

IsInstanceOf

isInstanceOf violates parametricity. Refactor so that the type is established statically.

// Won't compile: isInstanceOf is disabled
x.isInstanceOf[String]

JavaConversions

The standard library provides implicits conversions to and from Java types in scala.collection.JavaConversions. This can make code difficult to understand and read about. The explicit conversions provided by scala.collection.JavaConverters should be used instead.

// Won't compile: scala.collection.JavaConversions is disabled
import scala.collection.JavaConversions._
val scalaMap: Map[String, String] = Map()
val javaMap: java.util.Map[String, String] = scalaMap

JavaSerializable

java.io.Serializable is a common subtype to many structures, especially those imported from Java. For example, String is a subtype of java.io.Serializable but not scala.Serializable. The Scala compiler loves to infer java.io.Serializable as a common supertype, but that is almost always incorrect. Explicit type arguments should be used instead.

// Won't compile: Inferred type containing java.io.Serializable
object O extends Serializable
val mistake = List("foo", "bar", O /* forgot O.toString */)

LeakingSealed

Descendants of a sealed type must be final or sealed. Otherwise this type can be extended in another file through its descendant.

file 1:
// Won't compile: Descendants of a sealed type must be final or sealed
sealed trait t
class c extends t

file 2:
class d extends c

MutableDataStructures

The standard library provides mutable collections. Mutation breaks equational reasoning.

// Won't compile: scala.collection.mutable package is disabled
import scala.collection.mutable.ListBuffer
val mutList = ListBuffer()

NonUnitStatements

Scala allows statements to return any type. Statements should only return Unit (this ensures that they’re really intended to be statements).

// Won't compile: Statements must return Unit
10
false

When interfacing with APIs that violate this principle, one can define a function in the project

@specialized def discard[A](evaluateForSideEffectOnly: A): Unit = {
  val _: A = evaluateForSideEffectOnly
  () //Return unit to prevent warning due to discarding value
}

discard{ badMutateFun(foo) } // Use like this

Nothing

Nothing is a special bottom type; it is a subtype of every other type. The Scala compiler loves to infer Nothing as a generic type but that is almost always incorrect. Explicit type arguments should be used instead.

// Won't compile: Inferred type containing Nothing
val nothing = ???
val nothingList = List.empty

Null

null is a special value that inhabits all reference types. It breaks type safety.

// Won't compile: null is disabled
val s: String = null
var s2: String = _

Option2Iterable

Scala inserts an implicit conversion from Option to Iterable. This can hide bugs and creates surprising situations like Some(1) zip Some(2) returning an Iterable[(Int, Int)].

OptionPartial

scala.Option has a get method which will throw if the value is None. The program should be refactored to use scala.Option#fold to explicitly handle both the Some and None cases.

Overloading

Method overloading may lead to confusion and usually can be avoided.

// Won't compile: Overloading is disabled
class c {
  def equals(x: Int) = {}
}

Product

Product is a type common to many structures; it is the supertype of case classes and tuples. The Scala compiler loves to infer Product as a generic type, but that is almost always incorrect. Explicit type arguments should be used instead.

// Won't compile: Inferred type containing Product
val any = List((1, 2, 3), (1, 2))

PublicInference

Type inference of public members can expose extra type information, that can break encapsulation.

class c {
  // Won't compile: Public member must have an explicit type ascription
  def f() = new c with t

  val name = "abc" // Compiles: fields initialized by string, char or boolean literals are ignored
}

class c2 extends c {
  override def f() = ... // Compiles: overridden members are ignored
}

Recursion

General recursion can result in non-termination. There are various techniques, like fixed-point combinators, that allow you to extract recursion from your code. Recursion can also cause problems with stack usage. This can often be fixed with a @tailrec annotation (which uses constant stack) or by using a trampoline (which moves stack usage to the heap).

// Won't compile: Potentially-diverging recursion.
def diverging(i: Int): Int = if (i == 0) 0 else diverging(i + 1)

This particular instance can be silenced by adding @tailrec before def, making the stack safety explicit.

Return

return breaks referential transparency. Refactor to terminate computations in a safe way.

// Won't compile: return is disabled
def foo(n:Int): Int = return n + 1
def foo(ns: List[Int]): Any = ns.map(n => return n + 1)

Serializable

Serializable is a type common to many structures. The Scala compiler loves to infer Serializable as a generic type, but that is almost always incorrect. Explicit type arguments should be used instead.

// Won't compile: Inferred type containing Serializable
val any = List((1, 2, 3), (1, 2))

StringPlusAny

Scala’s String interface provides a + method that converts the operand to a String via its toString method. As mentioned in the documentation for the ToString wart, this method is unreliable and brittle.

// Won't compile: Implicit conversion to string is disabled
"foo" + {}
{} + "bar"

Throw

throw implies partiality. Encode exceptions/errors as return values instead using Either.

ToString

Scala creates a toString method automatically for all classes. Since toString is based on the class name, any rename can potentially introduce bugs. This is especially pernicious for case objects. toString should be explicitly overridden wherever used.

case object Foo { override val toString = "Foo" }

IterableOps

scala.collection.Iterable has:

  • head,
  • tail,
  • init,
  • last,
  • reduce,
  • reduceLeft,
  • reduceRight,
  • max,
  • maxBy,
  • min and
  • minBy methods,

all of which will throw if the collection is empty. The program should be refactored to use:

  • headOption,
  • drop(1),
  • dropRight(1),
  • lastOption,
  • reduceOption or fold,
  • reduceLeftOption or foldLeft and
  • reduceRightOption or foldRight respectively,

to explicitly handle empty collections.

TripleQuestionMark

??? throws NotImplementedError. Encode exceptions/errors as return values instead using Either.

// Won't compile: ??? is disabled
def foo: Int = ???

TryPartial

scala.util.Try has a get method which will throw if the value is a Failure. The program should be refactored to use scala.util.Try#map and scala.util.Try#getOrElse to explicitly handle both the Success and Failure cases.

Unsafe

Checks for the following warts:

  • Any
  • AsInstanceOf
  • DefaultArguments
  • EitherProjectionPartial
  • IsInstanceOf
  • IterableOps
  • NonUnitStatements
  • Null
  • OptionPartial
  • Product
  • Return
  • Serializable
  • StringPlusAny
  • Throw
  • TripleQuestionMark
  • TryPartial
  • Var

This list is built from Unsafe.scala

Var

Mutation breaks equational reasoning.

// Won't compile: var is disabled
var x = 100

While

while loop usually indicates low-level code. If performance is not an issue, it can be replaced.

// Won't compile: while is disabled
while(i < 10) {
  i += 1
  ...
}