trait IsIterableLike[Repr] extends AnyRef
A trait which can be used to avoid code duplication when defining extension
methods that should be applicable both to existing Scala collections (i.e.,
types extending Iterable) as well as other (potentially user-defined)
types that could be converted to a Scala collection type. This trait
makes it possible to treat Scala collections and types that can be implicitly
converted to a collection type uniformly. For example, one can provide
extension methods that work both on collection types and on Strings (Strings
do not extend Iterable, but can be converted to Iterable)
IsIterable provides two members:
- type member
A, which represents the element type of the targetIterable[A] - value member
conversion, which provides a way to convert between the type we wish to add extension methods to,Repr, andIterable[A].
Usage
One must provide IsIterableLike as an implicit parameter type of an implicit
conversion. Its usage is shown below. Our objective in the following example
is to provide a generic extension method mapReduce to any type that extends
or can be converted to Iterable. In our example, this includes
String.
import scala.collection.Iterable import scala.collection.generic.IsIterableLike class ExtensionMethods[A, Repr](coll: IterableLike[A, Repr]) { def mapReduce[B](mapper: A => B)(reducer: (B, B) => B): B = { val iter = coll.toIterator var res = mapper(iter.next()) while (iter.hasNext) res = reducer(res, mapper(iter.next())) res } } implicit def withExtensions[Repr](coll: Repr)(implicit Iterable: IsIterableLike[Repr]) = new ExtensionMethods(Iterable.conversion(coll)) // See it in action! List(1, 2, 3).mapReduce(_ * 2)(_ + _) // res0: Int = 12 "Yeah, well, you know, that's just, like, your opinion, man.".mapReduce(x => 1)(_ + _) // res1: Int = 59
Here, we begin by creating a class ExtensionMethods which contains our
mapReduce extension method. Note that ExtensionMethods takes a constructor
argument coll of type IterableLike[A, Repr], where A represents the
element type and Repr represents (typically) the collection type. The
implementation of mapReduce itself is straightforward.
The interesting bit is the implicit conversion withExtensions, which
returns an instance of ExtensionMethods. This implicit conversion can
only be applied if there is an implicit value Iterable of type
IsIterableLike[Repr] in scope. Since IsIterableLike provides
value member conversion, which gives us a way to convert between whatever
type we wish to add an extension method to (in this case, Repr) and
IterableLike[A, Repr], we can now convert coll from type Repr
to IterableLike[A, Repr]. This allows us to create an instance of
the ExtensionMethods class, which we pass our new
IterableLike[A, Repr] to.
When the mapReduce method is called on some type of which it is not
a member, implicit search is triggered. Because implicit conversion
withExtensions is generic, it will be applied as long as an implicit
value of type IsIterableLike[Repr] can be found. Given that
IsIterableLike contains implicit members that return values of type
IsIterableLike, this requirement is typically satisfied, and the chain
of interactions described in the previous paragraph is set into action.
(See the IsIterableLike companion object, which contains a precise
specification of the available implicits.)
Note: Currently, it's not possible to combine the implicit conversion and the class with the extension methods into an implicit class due to limitations of type inference.
Implementing IsIterableLike for New Types
One must simply provide an implicit value of type IsIterableLike
specific to the new type, or an implicit conversion which returns an
instance of IsIterableLike specific to the new type.
Below is an example of an implementation of the IsIterableLike trait
where the Repr type is String.
implicit val stringRepr: IsIterableLike[String] { type A = Char } = new IsIterableLike[String] { type A = Char val conversion = implicitly[String => IterableOps[Char, Any, String]] }
- Alphabetic
- By Inheritance
- IsIterableLike
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Type Members
-
abstract
type
A
The type of elements we can traverse over.
Abstract Value Members
-
abstract
val
conversion: (Repr) ⇒ IterableOps[A, Iterable, Repr]
A conversion from the representation type
ReprtoIterableOps[A, Iterable, Repr].
Concrete Value Members
-
final
def
!=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
##(): Int
- Definition Classes
- AnyRef → Any
-
final
def
==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
asInstanceOf[T0]: T0
- Definition Classes
- Any
-
def
clone(): AnyRef
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @native() @throws( ... )
-
final
def
eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
def
equals(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
def
finalize(): Unit
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( classOf[java.lang.Throwable] )
-
final
def
getClass(): Class[_]
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
def
hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
final
def
isInstanceOf[T0]: Boolean
- Definition Classes
- Any
-
final
def
ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
final
def
notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
synchronized[T0](arg0: ⇒ T0): T0
- Definition Classes
- AnyRef
-
def
toString(): String
- Definition Classes
- AnyRef → Any
-
final
def
wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @throws( ... )