Barcelona
Barcelona

Reputation: 2132

Create custom Seq collection in Scala

I want to create a new custom Scala collection from existing Seq collection. I have a trait named Ref which holds the data as below

trait Ref[A] {
   def get: A
   def getAsOption: Option[A]
   def dataType: Class[A]
   // other methods
}

My custom collection named Vec which is a Sequence of Ref[A] (i.e Vec[A] equivalents to Seq[Ref[A]]), the reason I want to create a custom collection like this because I want to keep the type parameter of Ref in collection to process in custom methods. My code as below

trait VecLike[A, +Repr <: Seq[Ref[A]]]
  extends SeqLike[Ref[A], Repr]
  with TraversableLike[Ref[A], Repr] {
// custom methods
}

trait GenVec[A]
  extends VecLike[A, Seq[Ref[A]]]
  with Seq[Ref[A]]
  with PartialFunction[Int, Ref[A]]

abstract class AbstractVec[A](vec: Ref[A]*)
  extends AbstractSeq[Ref[A]]
  with GenVec[A] {...}

class Vec(vec: Ref[A]*)
  extends AbstractVec[A](vec:_*)
  with VecLike[A, Vec[A]]
  with GenericTraversableTemplate[Ref[A], Seq]

But when I call map() function

Vec(1,2,3,4).map(intToString) 

It returns a Seq[String], the expected result is Vec[String]. I also tried to create custom CanBuildFrom in companion object with SeqFactory[Seq] but it failed. :( :(

Can anybody give me some advices about this and how I implement to achieve this?

Upvotes: 2

Views: 1505

Answers (2)

Barcelona
Barcelona

Reputation: 2132

I finished it, that's my mistake I created wrong CanBuildFrom. Below is the full implementation with CanBuildFrom (CBF Inspired from Scala GenericCanBuildFrom)

trait VecLike[A, +Repr]
  extends SeqLike[Ref[A], Repr]

trait GenVec[A]
  extends AnyRef
  with VecLike[A, GenVec[A]]

trait Vec[A]
  extends GenVec[A]
  with VecLike[A, Vec[A]]

abstract class AbstractVec[A](vec: Seq[Ref[A]])
  extends AnyRef
  with Vec[A]

final class VecImpl[A](vec: Seq[Ref[A]])
  extends AbstractVec[A](vec)

object Vec {


  private[this] val VecCBFInstance: VecCanBuildFrom[Nothing] = new VecCanBuildFrom[Nothing] {
    override def apply() = newBuilder[Nothing]
  }
  private def VecCBF: VecCanBuildFrom[Nothing] = VecCBFInstance
  private class VecCanBuildFrom[A] extends CanBuildFrom[Vec[_], A, Vec[A]] {
    def apply(from: Vec[_]) = newBuilder[A]
    def apply() = newBuilder[A]
  }
  implicit def canBuildFrom[A]: CanBuildFrom[Vec[_], A, Vec[A]] = VecCBF.asInstanceOf[VecCanBuildFrom[A]]

}

Now I can receive Vec result instead of Seq after call map() function as below

val vec = Vec(1,2,3,4)
var vecStr : Vec[String] = vec.map(intToString)

Upvotes: 0

Dima
Dima

Reputation: 40500

You need to implement a custom Builder and make newBuilder method in VecLike return it. Check out this page for a very good tutorial on implementing custom collections: http://docs.scala-lang.org/overviews/core/architecture-of-scala-collections.html

Upvotes: 3

Related Questions