Reputation: 1739
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.
Upvotes: 3
Views: 517
Reputation: 39577
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.
Upvotes: 8