1

I have seen this solution work on the past, so I'm unsure what I'm doing wrong. Consider the answer of How does type class resolution in scala work?

out of it I did this code:

import org.specs2.mutable.Specification

case class OptionFinder[A](isOption: Boolean)

object OptionFinder extends LowerPriority {
  implicit def hitOption[A]: OptionFinder[Option[A]] = OptionFinder(true)
}

trait LowerPriority {
  implicit def notOption[A]: OptionFinder[A] = OptionFinder(false)
}

object OptionFinderSpec extends Specification {
  "OptionFinder" should {

    "find Options" in {
      def myFunction[A](value: A)(implicit optionFinder: OptionFinder[A]): Boolean = {
        optionFinder.isOption
      }

      myFunction(5) must beFalse
      myFunction(None) must beTrue
      myFunction(Some(5)) must beTrue
    }
  }
}

On my understanding, all tests should pass. For some reason both myFunction(None) must beTrue and myFunction(Some(5)) must beTrue fail

What am I doing wrong?

oleber
  • 1,089
  • 4
  • 12
  • 25

1 Answers1

2

Compiler is recognizing your parameters in those two cases as None and Some instead of as Option. It's tricky to have an implicit instance for "any A" because then you might be stumbling upon this situation quite often, where you expect some more specific type to be used (e.g. Option[A]), but you accidentally fall back to the implicit for the generic type (in this case A), and compiler cannot really know that it's not what you wanted.

So, this will work:

myFunction(Option.empty) must beTrue
myFunction(Option(5)) must beTrue

This will also work:

implicit def hitOption[A]: OptionFinder[Option[A]] = OptionFinder(true)
implicit def hitOptionN: OptionFinder[None.type] = OptionFinder(true)
implicit def hitOptionS[A]: OptionFinder[Some[A]] = OptionFinder(true)
...
myFunction(None) must beTrue
myFunction(Some(5)) must beTrue

You can blame the design of Option for this one. I'm pretty sure every single Scala developer has at least once encountered the problem "Option expected, but found Some". If you construct them using empty and apply you will be on the safe side.

slouc
  • 9,508
  • 3
  • 16
  • 41