I was recently surprised when invocations of Scala's implicitly
was returning null during runtime. I had thought that was unlikely, given that the code shouldn't compile if no implicit instance was available in implicit scope. When is implicitly allowed to return null? Is this a compiler limitation, or is this expected behavior?
Here's some context, if it helps. I'm using shapeless to derive typeclass instances for persisting arbitrary nested case classes. I thought it would be helpful to use implicitly in the nested case classes to check if a typeclass instance could be derived, as it can be unclear where to start looking if the nested case class is large.
So, for example, if I was trying to persist:
case class Foo(bar: Bar, baz: Baz)
and the compiler couldn't derive an instance for my formatter MyFormatter[Foo]
, I started doing something like the following:
case class Bar(i: Int, q: Qux)
object Bar {
implicit val formatter = implicitly[MyFormatter[Bar]]
}
expecting the compiler to tell me that it couldn't find an implicit instance of MyFormatter[Bar]
.
Instead, this was a terrible idea, and my code compiled (when it shouldn't have, as no typeclass instance for Qux could be derived) and Bar.formatter
was null at runtime.
MyFormatter
. Something is making that implicit, but it's impossible to say what without seeing it. The Scala compiler won't magically create one that isnull
on its own. – Michael Zajacimplicit val oyVey: MyFormatter[Bar] = null
(which I promise I didn't do) what would make that possible? – Josh Marcusimplicitly
grants no magic. You could tryprintln(scala.reflect.runtime.universe.reify(implicitly[MyFormatter[Foo]]))
to see where it is being resolved from. – Michael Zajac