8
votes

I don't understand the apparent contradictory behavior I'm seeing in the following code (Scala 2.9):

class Pimp1(val x : Double) {
  def pluss(that : Pimp1) = x + that.x
  def <(that : Pimp1) = x < that.x
}

object Pimp1 {
implicit def d2pimp(d : Double) = new Pimp1(d)
implicit def d2pimp(od : Option[Double]) = new Pimp1(od.get)
} 

object Scratch2 extends App {
    import Pimp1._

    5.0.pluss(Some(5.0))
    5.0 < Some(5.0)
}

The line '5.0.pluss(Some(5.0))' compiles, but the line after it does not compile with the following error message:

overloaded method value < with alternatives: (x: Double)Boolean (x: Float)Boolean (x: Long)Boolean (x: Int)Boolean (x: Char)Boolean (x: Short)Boolean (x: Byte)Boolean cannot be applied to (Some[Double])

If I add explicit < operator to the Pimp class that takes an Option[Double]:

def <(that : Option[Double]) = x < that.get

Everything compiles fine.

Now, the way I understand Scala implicit conversion rules, this makes perfect sense:

  1. The compiler understands that there's no '<' operator on Double that accepts Option[Double]
  2. It considers the implicit conversion to Pimp1.
  3. If Pimp1 has a suitable operator, it works, otherwise, it generates an error.
  4. Importantly, this demonstrates that the compiler does not consider applying a second (available) implicit conversion, from Option[Double] to Pimp.

This is how I expected things to work.

However, this seems to be contradicted by the first example, where:

  1. The compiler sees that there's no pluss method on Double.
  2. The compiler tries the implicit conversion to Pimp, which does have such a method.
  3. However, in order to make the operator work, the compiler has to apply a second implicit conversion, on the argument, to convert it to Pimp.

According to the logic above, this should not compile, but it does. Do the implicit conversion rules treat non-existing methods and non-matching methods differently?

1
It's interesting, because if you reverse it, it works: Some(5.0) < 5.0Noah

1 Answers

5
votes

This makes sense to me. The first one, that works goes like this:

Does Double have a pluss method? No, can we implicitly convert it to something that does? Yes. Ok, now I want to apply the pluss method. Does it take an Option? No. Can I implictly convert Option to soemthing that it does take? yes.

The second one goes like this:

Does Double have a < method? Yes. Does it take an Option? No. can I implicitly convert Option to something that < does take? No.