Adracus Adracus - 3 months ago 8
Scala Question

Implicit class for subtypes of a generic class

I want to enhance all

Iterable
s with some custom code.
For this I wrote the following:

implicit class RichIterable[A, B <: Iterable[A]](b: B) {
def nonEmptyOpt: Option[B] = if (b.nonEmpty) Some(b) else None
}


Now, when I want to use this method on a
List
that definitely is a subclass of
Iterable
like so

List(1, 2, 3).nonEmptyOpt


I get

value nonEmptyOpt is not a member of List[Int]


How can I resolve this?

Answer

Little trick I stumbled upon once:

scala> implicit class RichIterable[A, B <: Iterable[A]](b: B with Iterable[A]) {
 |   def nonEmptyOpt: Option[B] = if (b.nonEmpty) Some(b) else None
 | }
defined class RichIterable

scala> List(1,2,3).nonEmptyOpt
res3: Option[List[Int]] = Some(List(1, 2, 3))

Note the B with Iterable[A] on the parameter.

By the way, when debugging implicits, it helps sometimes to try to apply them explicitly (before change):

scala> new RichIterable(List(1,2,3)).nonEmptyOpt
<console>:15: error: inferred type arguments [Nothing,List[Int]] do not conform to class RichIterable's type parameter bounds [A,B <: Iterable[A]]
          new RichIterable(List(1,2,3)).nonEmptyOpt

So, the compiler is having a hard time figuring out the type of A. The type refinement apparently helps it along.

Comments