Hi there. I’m in a situation where I have a class with a generic parameter, and I need to restrict the types to those which I can create a “Default” instance for. In Rust, I would just put a T: Default
bound, then the caller would need to ensure that their type implements the Default
trait. I’ve looked around and I haven’t found much mention of use cases similar to mine. If there’s a standard way to do this that I haven’t found, please let me know but I’ll describe how I’m attempting to solve this now and what trouble I’m running into.
I recently discovered Context Bounds, which seemed like they should be able to solve my use case. My class setup looks like this:
trait Default[T] {
implicit def default(): T
}
case class Container[Payload](common: String, specialized: Payload)
object Container {
def emptyPayload[Payload: Default](common: String): Container[Payload] = {
Container(common, implicitly[Default[Payload]].default())
}
}
class MyAbstractClass[ClientPayload: Default](
protected val merger: (Container[ClientPayload], Container[ClientPayload]) => Container[ClientPayload],
) {
def doStuff(): Unit = {
val zero: Container.emptyPayload("some common value")
fold(zero)(merger)
// ...
}
}
class MyConcreteClass extends MyAbstractClass[MyPayload](MyConcreteClass.merger) {
// ...
}
object MyConcreteClass {
def merger // ...
case class MyPayload(/* fields */)
implicit object MyPayloadDefault extends Default[MyPayload] {
override implicit def default(): MyPayload = MyPayload(/* default values */)
}
}
The error I’m getting is
... could not find implicit value for evidence parameter of type com.my.package.Default[com.my.package.MyPayload]
I don’t know whether I have this almost right and the problem is something small (like scoping), or whether my approach is fundamentally flawed in some way. Some of the classes are located in separate files, but I did make sure to import the implicit MyPayloadDefault above the MyConcreteClass definition, like this:
import com.my.package.MyConcreteClass._
class MyConcreteClass extends MyAbstractClass[MyPayload](merger) { /* ... */ }
object MyConcreteClass {
implicit object MyPayloadDefault extends Default[MyPayload] { /* ... */ }
}
So it seems to me that the MyConcreteClass.MyPayloadDefault
should be in scope to satisfy the implicit requirement for MyAbstractClass, but it still seems not to be working.
If anybody has any clues as to what I’m doing wrong, I’d greatly appreciate it!