Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Unify strict and lazy building #114

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 71 additions & 39 deletions src/main/scala/strawman/collection/Factories.scala
Original file line number Diff line number Diff line change
@@ -1,133 +1,165 @@
package strawman
package collection

import strawman.collection.mutable.Builder
import scala.language.implicitConversions

import strawman.collection.mutable.{ArrayBuffer, Builder}

import scala.{Any, Int, Nothing, Ordering}
import scala.annotation.unchecked.uncheckedVariance


/** Builds a collection of type `C` from elements of type `A` when a source collection of type `From` is available.
* Implicit instances of `BuildFrom` are available for all collection types.
*
* @tparam From Type of source collection
* @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.)
* @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.)
*/
trait BuildFrom[-From, -A, +C] extends Any {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does making the C a type parameter instead of a type member do for us?

Copy link
Contributor Author

@szeiger szeiger Jun 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer a type member (and I did use one in my original implementation in #45) but FromSpecificIterable in Martin's simplified version uses a type parameter so I used the same here. I think we should use type members for both. Unlike CanBuildFrom, lookup for BuildFrom and FromSpecificIterable is never determined by this type. It is strictly an "out" parameter.

def fromSpecificIterable(from: From)(it: Iterable[A]): C

/** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
* Building collections with `fromSpecificIterable` is preferred because it can be lazy for lazy collections. */
def newBuilder(from: From): Builder[A, C]
}

object BuildFrom extends BuildFromLowPriority {
/** Build the source collection type from a MapOps */
implicit def buildFromMapOps[CC[K, V] <: Map[K, V] with MapOps[K, V, CC, _], A, B, E, F]: BuildFrom[CC[A, B], (E, F), CC[E, F]] = new BuildFrom[CC[A, B], (E, F), CC[E, F]] {
//TODO: Reuse a prototype instance
def newBuilder(from: CC[A, B]): Builder[(E, F), CC[E, F]] = from.mapFactory.newBuilder[E, F]()
def fromSpecificIterable(from: CC[A, B])(it: Iterable[(E, F)]): CC[E, F] = from.mapFactory.fromIterable(it)
}

/** Build the source collection type from a SortedMapOps */
implicit def buildFromSortedMapOps[CC[K, V] <: SortedMap[K, V] with SortedMapOps[K, V, CC, _], A, B, E : Ordering, F]: BuildFrom[CC[A, B], (E, F), CC[E, F]] = new BuildFrom[CC[A, B], (E, F), CC[E, F]] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most people won't have to look at this, but it's still pretty imposing with seven (?!) separate type parameters (five "real", two parameterizing CC).

def newBuilder(from: CC[A, B]): Builder[(E, F), CC[E, F]] = from.sortedMapFactory.newBuilder[E, F]()
def fromSpecificIterable(from: CC[A, B])(it: Iterable[(E, F)]): CC[E, F] = from.sortedMapFactory.fromSpecificIterable(it)
}
}

trait BuildFromLowPriority {
/** Build the source collection type from an IterableOps */
implicit def buildFromIterableOps[CC[X] <: Iterable[X] with IterableOps[X, CC, _], A, E]: BuildFrom[CC[A], E, CC[E]] = new BuildFrom[CC[A], E, CC[E]] {
//TODO: Reuse a prototype instance
def newBuilder(from: CC[A]): Builder[E, CC[E]] = from.iterableFactory.newBuilder[E]()
def fromSpecificIterable(from: CC[A])(it: Iterable[E]): CC[E] = from.iterableFactory.fromIterable(it)
}

/** Build the source collection type from an Iterable with SortedOps */
implicit def buildFromSortedOps[CC[X] <: Iterable[X] with SortedOps[X, CC[X], CC], A, E : Ordering]: BuildFrom[CC[A], E, CC[E]] = new BuildFrom[CC[A], E, CC[E]] {
def newBuilder(from: CC[A]): Builder[E, CC[E]] = from.sortedIterableFactory.newBuilder[E]()
def fromSpecificIterable(from: CC[A])(it: Iterable[E]): CC[E] = from.sortedIterableFactory.fromSpecificIterable(it)
}
}

/**
* Builds a collection of type `C` from elements of type `A`
* @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.)
* @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.)
*/
trait FromSpecificIterable[-A, +C] extends Any {
trait FromSpecificIterable[-A, +C] extends Any with BuildFrom[Any, A, C] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do we rely on the fact that FromSpecificIterable is a BuildFrom?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever you pass a factory object instead of an implicit BuildFrom. All factories provide an implicit conversion to FromSpecificIterable.

def fromSpecificIterable(from: Any)(it: Iterable[A]): C = fromSpecificIterable(it)
def fromSpecificIterable(it: Iterable[A]): C
def newBuilder(from: Any): Builder[A, C] = newBuilder
def newBuilder: Builder[A, C]
}

/** Base trait for companion objects of unconstrained collection types */
trait IterableFactory[+CC[_]] {

def fromIterable[E](it: Iterable[E]): CC[E]

def empty[A]: CC[A]

def apply[A](xs: A*): CC[A] = fromIterable(View.Elems(xs: _*))

def fill[A](n: Int)(elem: => A): CC[A] = fromIterable(View.Fill(n)(elem))

}

trait IterableFactoryWithBuilder[+CC[_]] extends IterableFactory[CC] {
def newBuilder[A](): Builder[A, CC[A]]
def newBuilder[A](): Builder[A, CC[A]] = new ArrayBuffer[A]().mapResult(fromIterable _)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not sure this default implementation will be useful. Will it be useful elsewhere than for ArrayBuffer and ImmutableArray?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This default is used for all collection types that cannot provide a better builder. This includes all lazy collections.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of lazy collections, what about using an ImmutableArray instead of an ArrayBuffer to avoid the extra space?

Copy link
Contributor Author

@szeiger szeiger Jun 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't know the size ahead of time so you can either copy everything again or live with some wasted space.

Copy link
Contributor

@julienrf julienrf Jun 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that even after an ArrayBuffer has been completely built there might still be some unused extra space. If you build an ImmutableArray (or just call toArray on the ArrayBuffer, which is almost exactly the same thing), then you trim the end of the buffer. (But yes, that means one additional copy)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any precedent for this in other collection methods? AFAIK trimming to the current size is always an explicit operation. The default is to avoid copying at the expense of some unused space.

}

object IterableFactory {
import scala.language.implicitConversions

implicit def toSpecific[A, CC[_]](factory: IterableFactory[CC]): FromSpecificIterable[A, CC[A]] =
new FromSpecificIterable[A, CC[A]] {
def fromSpecificIterable(it: Iterable[A]): CC[A] = factory.fromIterable[A](it)
def newBuilder: Builder[A, CC[A]] = factory.newBuilder[A]()
}

class Delegate[CC[_]](delegate: IterableFactory[CC]) extends IterableFactory[CC] {
def empty[A]: CC[A] = delegate.empty
def fromIterable[E](it: Iterable[E]): CC[E] = delegate.fromIterable(it)
override def newBuilder[A](): Builder[A, CC[A]] = delegate.newBuilder[A]()
}

}

trait SpecificIterableFactory[-A, +C] extends FromSpecificIterable[A, C] {
def empty: C

def apply(xs: A*): C = fromSpecificIterable(View.Elems(xs: _*))

def fill(n: Int)(elem: => A): C = fromSpecificIterable(View.Fill(n)(elem))
def newBuilder: Builder[A, C] = new ArrayBuffer[A]().mapResult(fromSpecificIterable _)
}

/** Factory methods for collections of kind `* −> * -> *` */
trait MapFactory[+CC[X, Y]] {

def empty[K, V]: CC[K, V]
def fromIterable[K, V](it: Iterable[(K, V)]): CC[K, V]

def apply[K, V](elems: (K, V)*): CC[K, V] = fromIterable(elems.toStrawman)
def newBuilder[K, V](): Builder[(K, V), CC[K, V]] = new ArrayBuffer[(K, V)]().mapResult(fromIterable _)
}

object MapFactory {
import scala.language.implicitConversions

implicit def toSpecific[K, V, CC[X, Y]](factory: MapFactory[CC]): FromSpecificIterable[(K, V), CC[K, V]] =
new FromSpecificIterable[(K, V), CC[K, V]] {
def fromSpecificIterable(it: Iterable[(K, V)]): CC[K, V] = factory.fromIterable[K, V](it)
def newBuilder: Builder[(K, V), CC[K, V]] = factory.newBuilder[K, V]()
}

class Delegate[C[X, Y]](delegate: MapFactory[C]) extends MapFactory[C] {
def fromIterable[K, V](it: Iterable[(K, V)]): C[K, V] = delegate.fromIterable(it)
def empty[K, V]: C[K, V] = delegate.empty
override def newBuilder[K, V](): Builder[(K, V), C[K, V]] = delegate.newBuilder()
}

}

/** Base trait for companion objects of collections that require an implicit evidence */
trait SortedIterableFactory[+CC[_]] {

def sortedFromIterable[E : Ordering](it: Iterable[E]): CC[E]

def empty[A : Ordering]: CC[A]

def apply[A : Ordering](xs: A*): CC[A] = sortedFromIterable(View.Elems(xs: _*))

def fill[A : Ordering](n: Int)(elem: => A): CC[A] = sortedFromIterable(View.Fill(n)(elem))
def newBuilder[A : Ordering](): Builder[A, CC[A]] = new ArrayBuffer[A]().mapResult(sortedFromIterable[A] _)
}

object SortedIterableFactory {
import scala.language.implicitConversions

implicit def toSpecific[A: Ordering, CC[_]](factory: SortedIterableFactory[CC]): FromSpecificIterable[A, CC[A]] =
new FromSpecificIterable[A, CC[A]] {
def fromSpecificIterable(it: Iterable[A]): CC[A] = factory.sortedFromIterable[A](it)
def newBuilder: Builder[A, CC[A]] = factory.newBuilder[A]()
}

class Delegate[CC[_]](delegate: SortedIterableFactory[CC]) extends SortedIterableFactory[CC] {
def empty[A : Ordering]: CC[A] = delegate.empty
def sortedFromIterable[E : Ordering](it: Iterable[E]): CC[E] = delegate.sortedFromIterable(it)
override def newBuilder[A : Ordering](): Builder[A, CC[A]] = delegate.newBuilder[A]()
}

}

/** Factory methods for collections of kind `* −> * -> *` which require an implicit evidence value for the key type */
trait SortedMapFactory[+CC[X, Y]] {

def empty[K : Ordering, V]: CC[K, V]

def sortedFromIterable[K : Ordering, V](it: Iterable[(K, V)]): CC[K, V]

def apply[K : Ordering, V](elems: (K, V)*): CC[K, V] =
sortedFromIterable(elems.toStrawman)
def newBuilder[K : Ordering, V](): Builder[(K, V), CC[K, V]] = new ArrayBuffer[(K, V)]().mapResult(sortedFromIterable[K, V] _)
}

object SortedMapFactory {
import scala.language.implicitConversions

implicit def toSpecific[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]): FromSpecificIterable[(K, V), CC[K, V]] =
implicit def toSpecific[K : Ordering, V, CC[X, Y]](factory: SortedMapFactory[CC]): FromSpecificIterable[(K, V), CC[K, V]] =
new FromSpecificIterable[(K, V), CC[K, V]] {
def fromSpecificIterable(it: Iterable[(K, V)]): CC[K, V] = factory.sortedFromIterable(it)
def fromSpecificIterable(it: Iterable[(K, V)]): CC[K, V] = factory.sortedFromIterable[K, V](it)
def newBuilder: Builder[(K, V), CC[K, V]] = factory.newBuilder[K, V]()
}

class Delegate[CC[_, _]](delegate: SortedMapFactory[CC]) extends SortedMapFactory[CC] {
def empty[K: Ordering, V]: CC[K, V] = delegate.empty[K, V]
def sortedFromIterable[K: Ordering, V](it: Iterable[(K, V)]): CC[K, V] = delegate.sortedFromIterable(it)
class Delegate[C[X, Y]](delegate: SortedMapFactory[C]) extends SortedMapFactory[C] {
def sortedFromIterable[K : Ordering, V](it: Iterable[(K, V)]): C[K, V] = delegate.sortedFromIterable(it)
def empty[K : Ordering, V]: C[K, V] = delegate.empty
override def newBuilder[K : Ordering, V](): Builder[(K, V), C[K, V]] = delegate.newBuilder()
}

}
1 change: 1 addition & 0 deletions src/main/scala/strawman/collection/Iterable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ trait IterableOps[+A, +CC[X], +C] extends Any {
}

/** Base trait for strict collections that can be built using a builder.
*
* @tparam A the element type of the collection
* @tparam C the type of the underlying collection
*/
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/strawman/collection/Map.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ trait MapOps[K, +V, +CC[X, Y] <: Map[X, Y], +C <: Map[K, V]]
/** Similar to fromIterable, but returns a Map collection type */
protected[this] def mapFromIterable[K2, V2](it: Iterable[(K2, V2)]): CC[K2, V2]

def mapFactory: MapFactory[CC]

/** Optionally returns the value associated with a key.
*
* @param key the key value
Expand Down
6 changes: 5 additions & 1 deletion src/main/scala/strawman/collection/SortedMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ trait SortedMap[K, +V]

trait SortedMapOps[K, +V, +CC[X, Y] <: SortedMap[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMap[K, V]]
extends MapOps[K, V, Map, C]
with SortedOps[K, C] {
with SortedOps[K, C, SortedSet] {

def sortedIterableFactory = SortedSet

def sortedMapFactory: SortedMapFactory[CC]

protected[this] def sortedMapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn’t this be implemented?

protected[this] def sortedMapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = sortedMapFactory.sortedFromIterable(it)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think we can delegate this methods now the same way it is already done for fromSpecificIterable.


Expand Down
4 changes: 3 additions & 1 deletion src/main/scala/strawman/collection/SortedOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package strawman.collection
import scala.{Ordering, Option, Some}

/** Base trait for sorted collections */
trait SortedOps[A, +C] {
trait SortedOps[A, +C, +CC[_]] {

implicit def ordering: Ordering[A]

def sortedIterableFactory: SortedIterableFactory[CC]

/** Returns the first key of the collection. */
def firstKey: A

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/strawman/collection/SortedSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ trait SortedSet[A] extends Set[A] with SortedSetOps[A, SortedSet, SortedSet[A]]

trait SortedSetOps[A, +CC[X], +C <: SortedSet[A]]
extends SetOps[A, Set, C]
with SortedOps[A, C] {
with SortedOps[A, C, CC] {

protected[this] def sortedFromIterable[B: Ordering](it: Iterable[B]): CC[B]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be possible to implement this by delegating to sortedIterableFactory.


Expand Down
1 change: 1 addition & 0 deletions src/main/scala/strawman/collection/immutable/BitSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ sealed abstract class BitSet
def empty: BitSet = BitSet.empty

def iterableFactory = Set
def sortedIterableFactory = SortedSet

protected[this] def fromSpecificIterable(coll: collection.Iterable[Int]): BitSet = BitSet.fromSpecificIterable(coll)
protected[this] def sortedFromIterable[B : Ordering](it: collection.Iterable[B]): SortedSet[B] = SortedSet.sortedFromIterable(it)
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/strawman/collection/immutable/HashMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ sealed trait HashMap[K, +V]
import HashMap.{bufferSize, liftMerger, Merger, MergeFunction, nullToEmpty}

def iterableFactory = List
def mapFactory = HashMap

protected[this] def fromSpecificIterable(coll: collection.Iterable[(K, V)]): HashMap[K, V] = HashMap.fromIterable(coll)

Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/strawman/collection/immutable/List.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ case object Nil extends List[Nothing] {
override def tail: Nothing = throw new UnsupportedOperationException("tail of empty list")
}

object List extends IterableFactoryWithBuilder[List] {
object List extends IterableFactory[List] {

def fromIterable[B](coll: collection.Iterable[B]): List[B] = coll match {
case coll: List[B] => coll
case _ => ListBuffer.fromIterable(coll).toList
}

def newBuilder[A](): Builder[A, List[A]] = new ListBuffer[A].mapResult(_.toList)
override def newBuilder[A](): Builder[A, List[A]] = new ListBuffer[A].mapResult(_.toList)

def empty[A]: List[A] = Nil
}
1 change: 1 addition & 0 deletions src/main/scala/strawman/collection/immutable/ListMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ sealed class ListMap[K, +V]
with Serializable {

def iterableFactory = List
def mapFactory = ListMap

protected[this] def mapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)]): ListMap[K2,V2] = ListMap.fromIterable(it)

Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/strawman/collection/immutable/TreeMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ final class TreeMap[K, +V] private (tree: RB.Tree[K, V])(implicit val ordering:
def this()(implicit ordering: Ordering[K]) = this(null)(ordering)

def iterableFactory = List
def mapFactory = Map
def sortedMapFactory = TreeMap

protected[this] def fromSpecificIterable(coll: collection.Iterable[(K, V)]): TreeMap[K, V] =
TreeMap.sortedFromIterable(coll)
Expand Down
5 changes: 3 additions & 2 deletions src/main/scala/strawman/collection/immutable/TreeSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package strawman
package collection
package immutable

import mutable.Builder
import mutable.{ArrayBuffer, Builder}
import immutable.{RedBlackTree => RB}

import scala.{Boolean, Int, NullPointerException, Option, Ordering, Some, Unit}
Expand Down Expand Up @@ -63,6 +63,8 @@ final class TreeSet[A] private (tree: RB.Tree[A, Unit])(implicit val ordering: O

def iterableFactory = Set

def sortedIterableFactory = TreeSet

protected[this] def fromSpecificIterable(coll: strawman.collection.Iterable[A]): TreeSet[A] =
TreeSet.sortedFromIterable(coll)

Expand Down Expand Up @@ -112,5 +114,4 @@ object TreeSet extends SortedIterableFactory[TreeSet] {
case ts: TreeSet[E] => ts
case _ => empty[E] ++ it
}

}
4 changes: 2 additions & 2 deletions src/main/scala/strawman/collection/mutable/ArrayBuffer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class ArrayBuffer[A] private (initElems: Array[AnyRef], initLength: Int)
override def className = "ArrayBuffer"
}

object ArrayBuffer extends IterableFactoryWithBuilder[ArrayBuffer] {
object ArrayBuffer extends IterableFactory[ArrayBuffer] {

/** Avoid reallocation of buffer if length is known. */
def fromIterable[B](coll: collection.Iterable[B]): ArrayBuffer[B] =
Expand All @@ -136,7 +136,7 @@ object ArrayBuffer extends IterableFactoryWithBuilder[ArrayBuffer] {
}
else new ArrayBuffer[B] ++= coll

def newBuilder[A](): Builder[A, ArrayBuffer[A]] = new ArrayBuffer[A]()
override def newBuilder[A](): Builder[A, ArrayBuffer[A]] = new ArrayBuffer[A]()

def empty[A]: ArrayBuffer[A] = new ArrayBuffer[A]()
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/strawman/collection/mutable/BitSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class BitSet(protected[collection] final var elems: Array[Long])

def iterableFactory = Set

def sortedIterableFactory = SortedSet

protected[this] def sortedFromIterable[B : Ordering](it: collection.Iterable[B]): collection.mutable.SortedSet[B] =
collection.mutable.SortedSet.sortedFromIterable(it)

Expand Down
5 changes: 4 additions & 1 deletion src/main/scala/strawman/collection/mutable/Builder.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package strawman.collection.mutable

import scala.{Boolean, Any, Char, Unit}
import scala.{Any, Boolean, Char, Unit}
import java.lang.String

import strawman.collection.IterableOnce

import scala.math.Ordering

/** Base trait for collection builders */
trait Builder[-A, +To] extends Growable[A] { self =>

Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/strawman/collection/mutable/HashMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ final class HashMap[K, V] private[collection] (contents: HashTable.Contents[K, D
with MapOps[K, V, HashMap, HashMap[K, V]]
with Serializable {

def mapFactory = HashMap

private[this] val table: HashTable[K, V, DefaultEntry[K, V]] =
new HashTable[K, V, DefaultEntry[K, V]] {
def createNewEntry(key: K, value: V): DefaultEntry[K, V] = new Entry(key, value)
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/strawman/collection/mutable/HashSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ final class HashSet[A](contents: FlatHashTable.Contents[A])

}

object HashSet extends IterableFactoryWithBuilder[HashSet] {
object HashSet extends IterableFactory[HashSet] {

def fromIterable[B](it: strawman.collection.Iterable[B]): HashSet[B] = Growable.fromIterable(empty[B], it)

def empty[A]: HashSet[A] = new HashSet[A]

def newBuilder[A](): Builder[A, HashSet[A]] = new GrowableBuilder[A, HashSet[A]](empty)
override def newBuilder[A](): Builder[A, HashSet[A]] = new GrowableBuilder[A, HashSet[A]](empty)

}
Loading