Generic[A] where A is a Class?

240 views Asked by At

Using Shapeless, I tried to get a Generic[F] via:

import shapeless._

class F(x: Int)

but it failed:

scala> Generic[F]
<console>:20: error: could not find implicit value for parameter gen: shapeless.Generic[F]
       Generic[F]
              ^

Can shapeless produce a Generic[F]? If so, how?

1

There are 1 answers

0
Travis Brown On BEST ANSWER

What representation would you want for F? You could say it should be HNil, but the x isn't be visible outside of the body of the class, so Shapeless makes the decision not to provide any instance at all. This is "just" a design decision—the right one in my view, but it's easy to imagine Shapeless providing the HNil instance for your class.

It would also be reasonably easy to define your own instance for F, which is possible because Generic is just another type class:

import shapeless._

class F(x: Int)

object F {
  implicit val genericF: Generic.Aux[F, HNil] = new Generic[F] {
    type Repr = HNil

    def from(r: HNil): F = new F(0)
    def to(t: F): HNil = HNil
  }
}

As another answer notes, you can get Shapeless to provide an instance for you by changing your class to a case class. That's not the only way, though—you could also change the constructor parameter to a val or just remove it:

scala> class F(val x: Int)
defined class F

scala> shapeless.Generic[F]
res0: shapeless.Generic[F]{type Repr = shapeless.::[Int,shapeless.HNil]} = anon$macro$3$1@73e5dfa9

scala> class F()
defined class F

scala> shapeless.Generic[F]
res1: shapeless.Generic[F]{type Repr = shapeless.HNil} = anon$macro$5$1@4e0e355c

You couldn't make the parameter a var or make the class abstract, though (unless it was sealed and had case class or object implementations). Or rather you could, but then you'd have to define your own instances again, and you'd be breaking the contract in the Generic documentation, which says that the characterized type should be an "immutable data type that has a canonical way of constructing and deconstructing instances".

As far as I know the exact details of what kinds of arrangements of class definitions will get Generic instances isn't documented anywhere (and the source isn't easy reading), but it's pretty easy to test the limits you're interested in by trying out specific cases in the REPL.