Extending an object with a trait which needs implicit member
Asked Answered
O

1

1

I'm trying to have a code like below:

object MetaData extends CacheParams{}

So, since CacheParams needs implicit val p:Parameters, I tried:

object MetaData (implicit val p: Parameters) extends CacheParams

But it seems that I can't pass arguments to an object.

( because it gives error:traits or objects may not have parameters)

And if I don't pass any arguments it will give compile error that:

[error]: object creation impossible, since value p in trait CacheParams of type Parameters is not defined

I have no idea how to make this works. There were a few similar questions, but none of their answers solved my problem. Any help would be really appreciated. Thanks a lot.

Og answered 9/10, 2020 at 20:4 Comment(4)
Why not override p in the body of object?Illation
Yeah that would solve my problem. But I wanted to keep the object's body clean and decoupled from the configuration in Parameters, like the classes' bodies that accept the p: Parameters.Og
... or use a class instead of objectSamanthasamanthia
An object is a singleton it can not receive parameters because then it would allow creating multiple instances. So either use a class or fix the implicits in the object definition.Fishmonger
L
3

If I guessed the definition of CacheParams correctly

trait Parameters

trait CacheParams {
  implicit val p: Parameters
}

then you should: (1) replace the object

object MetaData /*(implicit val p: Parameters)*/ extends CacheParams

//object creation impossible. Missing implementation for:
//  implicit val p: Parameters // inherited from trait CacheParams

with a class

class MetaData(implicit val p: Parameters) extends CacheParams

or (2) implement the implicit inside the object

object MetaData extends CacheParams {
  override implicit val p: Parameters = new Parameters {}
}

or

implicit val params: Parameters = new Parameters {} // suppose an implicit is in current scope

object MetaData extends CacheParams {
  override implicit val p: Parameters = {
    val p = ??? // hiding above p to avoid ambiguous implicits, null or NPE, see (*) below
    implicitly[Parameters]
  }
}

(*) NullPointerException on implicit resolution

In (1) you're defining/resolving implicit now in current scope. In (2) you postpone resolving implicit till instantiating the class (resolving implicit in the scope of class constructor call site).

See also Pass implicit parameter through multiply objects

Yeah that would solve my problem. But I wanted to keep the object's body clean and decoupled from the configuration in Parameters, like the classes' bodies that accept the p: Parameters.

If in (1) you want to decouple the object from "the configuration in Parameters" you can try to introduce a trait (ParamsMaterializer):

object MetaData extends CacheParams with ParamsMaterializer

trait ParamsMaterializer {
  implicit val p: Parameters = new Parameters {}
}

or

implicit val params: Parameters = new Parameters {} // suppose an implicit is in current scope

object MetaData extends CacheParams with ParamsMaterializer

trait ParamsMaterializer {
  implicit val p: Parameters = {
    val p = ???
    implicitly[Parameters]
  }
}
Lackluster answered 9/10, 2020 at 23:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.