- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Creating custom collections that extend the new collections library?
Wed, 2009-09-02, 19:08
Hello.
I am having troubles creating custom collection that extend the new
collection library.
By copying exactly what existing collections do, I write the following
which works:
> trait C[T] extends Iterable[T] with TraversableClass[T, C] with
> IterableTemplate[T, C[T]] {
> override def companion: Companion[C] = C
> }
>
> object C extends TraversableFactory[C] {
> class Impl[T](buf: mutable.ArrayBuffer[T]) extends C[T] {
> def iterator: Iterator[T] = buf.iterator
> }
> implicit def builderFactory[T]: BuilderFactory[T, C[T], Coll] =
> new VirtualBuilderFactory[T]
> def newBuilder[T]: Builder[T, C[T]] =
> new mutable.ArrayBuffer[T] mapResult ( buf => new Impl[T](buf) )
> }
Now --- you can call me crazy if you want --- I want collection C to
only contain elements of a type P. Based on the example above, I add a
type constraints on T:
> 1 trait C[T <: P] extends Iterable[T] with TraversableClass[T, C]
> with IterableTemplate[T, C[T]] {
> 2 override def companion: Companion[C] = C
> 3 }
> 4
> 5 object C extends TraversableFactory[C] {
> 6 class Impl[T <: P](buf: mutable.ArrayBuffer[T]) extends C[T] {
> 7 def iterator: Iterator[T] = buf.iterator
> 8 }
> 9 implicit def builderFactory[T <: P]: BuilderFactory[T, C[T],
> Coll] =
> 10 new VirtualBuilderFactory[T]
> 11 def newBuilder[T <: P]: Builder[T, C[T]] =
> 12 new mutable.ArrayBuffer[T] mapResult ( buf => new Impl[T]
> (buf) )
> 13 }
Very very bad things happen:
> 1: illegal inheritance; trait C inherits different type instances
> of trait TraversableClass:
> scala.collection.generic.TraversableClass[T,C] and
> scala.collection.generic.TraversableClass[T,Iterable]
> 1: kinds of the type arguments (T,C) do not conform to the expected
> kinds of the type parameters (type A,type CC) in trait
> TraversableClass.
> C's type parameters do not match type CC's expected parameters:
> type T's bounds >: Nothing <: P are stricter than type X's declared
> bounds >: Nothing <: Any
> 2: overriding method companion in trait Iterable of type =>
> scala.collection.generic.Companion[Iterable]; method companion has
> incompatible type
> 2: kinds of the type arguments (C) do not conform to the expected
> kinds of the type parameters (type CC) in class Companion.
> C's type parameters do not match type CC's expected parameters:
> type T's bounds >: Nothing <: P are stricter than type X's declared
> bounds >: Nothing <: Any
> 5: kinds of the type arguments (C) do not conform to the expected
> kinds of the type parameters (type CC) in class TraversableFactory.
> C's type parameters do not match type CC's expected parameters:
> type T's bounds >: Nothing <: P are stricter than type X's declared
> bounds >: Nothing <: Any
> 6: illegal inheritance; class Impl inherits different type
> instances of trait TraversableClass:
> scala.collection.generic.TraversableClass[T,C] and
> scala.collection.generic.TraversableClass[T,Iterable]
> 11: overriding method newBuilder in class Companion of type [A]
> scala.collection.generic.Builder[A,C[A]];
> method newBuilder has incompatible type
It is difficult to know what the root cause of the problem is.
Arguably, all may be valid errors (as opposed to side-effects of other
errors). I don't know for sure.
The illegal inheritance errors for C and Impl are weird.
IterableTemplate pulls in a TraversableClass of its own through the
Traversable trait, but I can't see why adding a bound on T would
change anything there. Arguably, I do not actually understand how the
TraversableClass thingy (and its higher-kinded type parameter) works.
The errors on line 2, related to overriding companion make slightly
more sense: in Companion, there is no type bound on the type parameter
X of CC. On the other hand, I would have imagined that the higher-
kinded typer would unify these bounds into the Companion class. But I
may be misunderstanding something there.
As for the overriding of newBuilder, I can see how this is a problem.
Because the first type parameter of Builder is contra-variant (I don't
know why), passing T (which is a subtype of the type at the same place
in the overridden implementation) makes the returned builder type a
super-type of that it overrides, which is invalid.
Please, HELP! Does it mean that the new collection library does not
allow refining the element type when subclassing a collection? If this
is true, isn't that a little problem? If it is false, how can I do it,
and how can I read these error messages?
Cheers,
Gilles.