Search code examples
scalatypeclassimplicitshapeless

When can Scala's implicitly return null?


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.


Solution

  • Your implicit definition is recursive.

    scala> class C ; object C { implicit val cs: List[C] = implicitly[List[C]] }
    defined class C
    defined object C
    
    scala> C.cs
    res0: List[C] = null
    

    Not only is cs in scope, but object C is in implicit scope for List[C].

    Also, it's preferred to specify the type of implicits; sometimes it is necessary for inference to work; and someday it will be required.