Implicit class for subtypes of a general class

I want to improve all Iterable with special 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 that I want to use this method for List , which is definitely a subclass of Iterable , for example,

 List(1, 2, 3).nonEmptyOpt 

I get

 value nonEmptyOpt is not a member of List[Int] 

How can i solve this?

+5
source share
3 answers

Given a parameter with type B <: Iterable[A] , the compiler does not know how easy it is to understand what A , because it is not always easy to compute from B (you need to look for the smallest upper bounds).

Instead, you can do this by overriding type restrictions without using tricks. Essentially, B should really be a constructor of the type that is bounded above by Iterable . Then your implicit class is a conversion from some B[A] to your enriched class. Having the parameter B[A] helps the compiler to compute A , because it expects it to be an argument to a constructor of type 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 
+7
source

A little trick I came across 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 parameter B with Iterable[A] for the parameter.

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

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

So, the compiler has difficulty figuring out type A Clarification of the type seems to help him.

+7
source

A simpler solution would be the following:

 implicit class RichIterable[A](b: Iterable[A]) { def nonEmptyOpt: Option[Iterable[A]] = if (b.nonEmpty) Some(b) else None } scala> List(1,2,3).nonEmptyOpt res0: Option[Iterable[Int]] = Some(List(1, 2, 3)) 
0
source

All Articles