There are a couple of problems with your code:
Set[Int]()
is not a valid type for mySet
, you should drop the ()
- member
mySet
should be a val
, not a def
- you are calling apply() methods that don't exist
- if you want to hook in into the collections hierarchy at the Traversable level, you don't get methods like
+
and the derived +=
. If you're representing a set, then it should be a Set
.
Here's a revised attempt:
import mutable.Builder
import generic.CanBuildFrom
class MyClass private (val prop: String, private val mySet: Set[Int] = Set())
extends immutable.Set[Int] with SetLike[Int, MyClass] {
def -(elem: Int) = MyClass(prop, mySet - elem)
def +(elem: Int) = MyClass(prop, mySet + elem)
def contains(elem: Int) = mySet.contains(elem)
def iterator = mySet.iterator
override def empty: MyClass = MyClass(prop)
override def stringPrefix = "MyClass(" + prop + ")"
}
object MyClass {
def DefaultProp = "DefaultProp"
def apply(prop: String, mySet: Set[Int] = Set()) = new MyClass(prop, mySet)
def newBuilder(prop: String = DefaultProp): Builder[Int, MyClass] =
Set.newBuilder[Int] mapResult (set => MyClass(prop, set))
implicit def canBuildFrom: CanBuildFrom[MyClass, Int, MyClass] =
new CanBuildFrom[MyClass, Int, MyClass] {
def apply(): Builder[Int, MyClass] = newBuilder()
def apply(from: MyClass): Builder[Int, MyClass] = newBuilder(from.prop)
}
}
Then you can write:
var obj = MyClass("hello")
obj += 1
println(obj) // prints MyClass(hello)(1)
obj = obj map (_ + 1)
println(obj) // prints MyClass(hello)(2)
Let's dissect that:
MyClass
is now explicitly an immutable set with a custom representation declared in the type arguments to SetLike
. prop
is a public val member; the actual set, mySet
, is a private val.
Then we need to implement the four operations on which Set
relies, by simply forwarding them the mySet
. (This looks a like it could be factored out. For the Seq
s, there is a class SeqForwarder
that does a similar job; I couldn't find a SetForwarder
, though). Finally, we provide an empty
method, on which the built-in inherited builder also relies. Finally, overriding stringPrefix
enables a nicer string representation with "MyClass" and the value of prop
.
Note that The canBuildFrom
object MyClass
calls newBuilder
, passing the prop
of the original collection when it can. This means that most of the time, you can keep this value while mapping, etc. over MyClass
instances. We need to define a default value for prop
, however, since CanBuildFrom
s must define an apply
method that does not tell what the originating collection is. (Question: why would this actually happen?)
Finally, our implementation of newBuilder
does not rely on ArrayBuffer
s any more, but directly builds the Set
instance that will be wrapped by your new MyClass
instance.
Some more resources: