Avoid implicit conversions

Avoid implicit conversions like the plague they are.

Reason

Implicit conversions allow the compiler to treat values of a type as values of another type.

There’s at least one set of scenarios in which this is unambiguously bad: non-total conversions. That is, converting an A to a B when there exists As for which this conversion is impossible.

For example, String to Int:

implicit def str2int(str: String): Int = Integer.parseInt(str)

What this does is give the compiler a proof, as far as it’s concerned, that all Strings are Ints and he can accept the former where the later is expected.

Our proof is unfortunately flawed, and will result in runtime failures:

"foobar" / 2
// java.lang.NumberFormatException: For input string: "foobar"
// 	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
// 	at java.base/java.lang.Integer.parseInt(Integer.java:652)
// 	at java.base/java.lang.Integer.parseInt(Integer.java:770)
// 	at repl.Session$App$.str2int(implicit_conversions.md:8)
// 	at repl.Session$App$$anonfun$1.apply$mcI$sp(implicit_conversions.md:15)
// 	at repl.Session$App$$anonfun$1.apply(implicit_conversions.md:15)
// 	at repl.Session$App$$anonfun$1.apply(implicit_conversions.md:15)

Exceptions to the rule

Total conversions are more palatable - they shouldn’t result in runtime failures, at least.

One common scenario is adding methods to an existing type:

implicit class ExtendedInt(i: Int) {
  def add1: Int = i + 1
}

Which lets us run:

1.add1
// res0: Int = 2

In this scenario, all Ints can be converted to ExtendedInt: the conversion is total and cannot result in runtime failure.

Checked by

LinterRule
WartRemover