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 Seqs, 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 CanBuildFroms 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 ArrayBuffers any more, but directly builds the Set instance that will be wrapped by your new MyClass instance.
Some more resources: