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?
Given a parameter with only type B <: Iterable[A]
, the compiler doesn't know how to easily figure out what A
is, because it is not necessarily easily computed from B
(needing to search for least upper-bounds).
Instead you can do this by redefining the type constraints, without using tricks. Essentially, B
should really be a type constructor that is bounded above by Iterable
. Then, your implicit class is a conversion from some B[A]
to your enriched class. Having a parameter of B[A]
helps the compiler compute A
, because it expects it to be the argument of the type constructor B
.
implicit class RichIterable[A, B[X] <: Iterable[X]](b: B[A]) {
def nonEmptyOpt: Option[B[A]] = if (b.nonEmpty) Some(b) else None
}
scala> List(1, 2, 3).nonEmptyOpt
res0: Option[List[Int]] = Some(List(1, 2, 3))
scala> List.empty[Int].nonEmptyOpt
res1: Option[List[Int]] = None
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With