Implicit abstract constructor class parameter and inheritance in Scala

I am new to Scala and trying to learn and understand implicit conversions and parameters and came across a script that I find confusing.

For context, I use Scaldi to inject dependencies in an Akka application and would like multiple injection entities to inherit from an abstract class. I believe that I cannot make an abstract class a trait precisely because we need to make an implicit Injector accessible through the constructor argument in order to use the framework.

A very contrived example demonstrating the behavior that I see is as follows:

 class SecretSauce {} abstract class Base(implicit secretSauce: SecretSauce) {} class Concrete extends Base {} object Example extends App { ... // Setup Actor system, etc, etc implicit val secretSauce: SecretSauce = new SecretSauce() } 

I expected everything to work, but instead I get a compilation error:

 Unspecified value parameter secretSauce. class Concrete extends Base { ^ 

If I add an implicit parameter to a specific class, for example, everything will work:

 class Concrete(implicit secretSauce: SecretSauce) extends Base {} 

I think my confusion stems from the way implicit parameters work - in situations like the description, are they not inherited by child classes? Can someone ELI5 what is happening in my example, or point me to a link that can help clarify the situation?

Thanks!

+6
source share
2 answers

The exact rules governing where the Scala compiler searches for implicits are quite complex, but in most situations you only need to think about two places that implicit values ​​can come from:

  • Current area.
  • Companion objects for any type.

This means that this will compile:

 class SecretSauce {} object SecretSauce { implicit val secretSauce: SecretSauce = new SecretSauce() } abstract class Base(implicit secretSauce: SecretSauce) {} object Example extends App { class Concrete extends Base {} } 

Or that:

 class SecretSauce {} abstract class Base(implicit secretSauce: SecretSauce) {} object Example extends App { implicit val secretSauce: SecretSauce = new SecretSauce() class Concrete extends Base {} } 

In your version, however, when the compiler gets to this line:

 class Concrete extends Base {} 

He will know that he needs to find the implicit value of SecretSauce , and he will first look at the implicit values ​​in the scope in this line and then in the companion SecretSauce object (if it exists). It also does not find, so it refuses to compile your code.

+2
source

The implicit parameter gets "resolved" from:

  • Implications defined in the current area
  • Explicit Import
  • Import lookups

To define class Concrete , as I understand it, it is implicitly necessary to define or import.

I find a very good explanation in this SO answer .

+1
source

All Articles