Skip to content

Commit 9f58c61

Browse files
committed
Add strict version of Build, unify Build & CanBuild
1 parent f6ee4d4 commit 9f58c61

File tree

4 files changed

+66
-34
lines changed

4 files changed

+66
-34
lines changed

src/main/scala/strawman/collection/Iterable.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ trait IterableOps[+A] extends Any {
9696
def to[F <: BuildConstrained](fi: F)(implicit c: fi.Constraint[A @uncheckedVariance]): c.To[A @uncheckedVariance] =
9797
c.fromIterable(coll)
9898

99-
def to[C[_], Ev[_]](fi: ConstrainedFromIterable[C, Ev])(implicit ev: Ev[A @uncheckedVariance]): C[A @uncheckedVariance] =
100-
fi.constrainedFromIterable(coll)
99+
// Could be defined in addition to the method above; less generic but doesn't have to wrap the evidence
100+
//def to[C[_], Ev[_]](fi: ConstrainedFromIterable[C, Ev])(implicit ev: Ev[A @uncheckedVariance]): C[A @uncheckedVariance] =
101+
// fi.constrainedFromIterable(coll)
101102

102103
/** Convert collection to array. */
103104
def toArray[B >: A: ClassTag]: Array[B] =

src/main/scala/strawman/collection/IterableFactories.scala

+38-15
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,24 @@ package collection
33

44
import strawman.collection.mutable.Builder
55

6-
import scala.{Any, Int}
6+
import scala.{Any, Int, Nothing}
77
import scala.annotation.unchecked.uncheckedVariance
88

99
/** Instances of Build[B] can build some kind of collection from values of type B. */
1010
trait Build[-B] {
1111
type To[_]
1212
def fromIterable[E <: B](it: Iterable[E]): To[E]
1313
}
14+
trait BuildStrict[-B] extends Build[B] {
15+
def newBuilder[E <: B]: Builder[E, To[E]]
16+
}
1417

18+
/** Instances of BuildConstrained can build some kind of collection from values with an implicit constraint. */
1519
trait BuildConstrained {
16-
trait Constraint[E] extends Build[E]
20+
trait Constraint[E] <: Build[E]
21+
}
22+
trait BuildStrictConstrained extends BuildConstrained {
23+
trait Constraint[E] extends super.Constraint[E] with BuildStrict[E]
1724
}
1825

1926
/** Base trait for instances that can construct a collection from an iterable */
@@ -24,12 +31,12 @@ trait FromIterable[+C[_]] extends Build[Any] {
2431

2532
/** Base trait for instances that can construct a collection from an iterable by using an implicit evidence
2633
* for the element type. */
27-
trait ConstrainedFromIterable[+CC[_], Ev[_]] {
34+
trait ConstrainedFromIterable[+CC[_], Ev[_]] extends BuildConstrained {
2835
def constrainedFromIterable[E : Ev](it: Iterable[E]): CC[E]
2936
}
3037

3138
/** Base trait for companion objects of unconstrained collection types */
32-
trait IterableFactory[+C[_]] extends FromIterable[C] { self =>
39+
trait IterableFactory[+C[_]] extends FromIterable[C] with BuildStrict[Any] { self =>
3340
def empty[A]: C[A] = fromIterable(View.Empty)
3441

3542
def apply[A](xs: A*): C[A] = fromIterable(View.Elems(xs: _*))
@@ -38,21 +45,33 @@ trait IterableFactory[+C[_]] extends FromIterable[C] { self =>
3845

3946
def newBuilder[A]: Builder[A, C[A]]
4047

41-
protected[this] lazy val canBuildProto: CanBuild[Any, C[Any]] = new CanBuild[Any, C[Any]] {
42-
def fromIterable(it: Iterable[Any]): C[Any] = self.fromIterable[Any](it)
43-
def newBuilder: Builder[Any, C[Any]] = self.newBuilder[Any]
48+
protected[this] lazy val buildFromProto: BuildFrom[C[Any], Any] = new BuildFrom[C[Any], Any] {
49+
type To[_] = C[Any]
50+
def fromIterable[E](it: Iterable[E]): C[Any] = self.fromIterable[Any](it)
51+
def newBuilder[E]: Builder[E, C[Any]] = self.newBuilder[Any]
4452
}
4553

46-
implicit def canBuild[E]: CanBuild[E, C[E]] = canBuildProto.asInstanceOf[CanBuild[E, C[E]]]
54+
implicit def buildFrom[F, E]: BuildFrom[C[F], E] { type To[_] <: C[E] } =
55+
buildFromProto.asInstanceOf[BuildFrom[C[F], E] { type To[_] <: C[E] }]
56+
57+
def buildFromAny[E]: BuildFrom[Nothing, E] { type To[_] <: C[E] } =
58+
buildFromProto.asInstanceOf[BuildFrom[Nothing, E] { type To[_] <: C[E] }]
4759
}
4860

49-
trait CanBuild[E, +Repr] {
50-
def fromIterable(it: Iterable[E]): Repr
51-
def newBuilder: Builder[E, Repr]
61+
/** Implicit instances of this type are available for building arbitrary collection types */
62+
trait BuildFrom[+Repr, E] extends BuildStrict[E] { self =>
63+
def any: BuildFrom[Nothing, E] { type To[X] = self.To[X] } = this.asInstanceOf[BuildFrom[Nothing, E] { type To[X] = self.To[X] }]
5264
}
5365

5466
/** Base trait for companion objects of collections that require an implicit evidence */
55-
trait ConstrainedIterableFactory[+CC[X], Ev[_]] extends ConstrainedFromIterable[CC, Ev] {
67+
trait ConstrainedIterableFactory[+CC[X], Ev[_]] extends ConstrainedFromIterable[CC, Ev] with BuildStrictConstrained {
68+
69+
class ConstraintImpl[E : Ev] extends Constraint[E] {
70+
type To[_] = CC[E] @uncheckedVariance
71+
def fromIterable[X <: E](it: Iterable[X]): CC[E] = constrainedFromIterable[E](it)
72+
def newBuilder[X <: E]: Builder[X, CC[E]] = constrainedNewBuilder[E]
73+
}
74+
implicit def constraint[E : Ev]: ConstraintImpl[E] = new ConstraintImpl[E]
5675

5776
def empty[A : Ev]: CC[A] = constrainedFromIterable(View.Empty)
5877

@@ -62,8 +81,12 @@ trait ConstrainedIterableFactory[+CC[X], Ev[_]] extends ConstrainedFromIterable[
6281

6382
def constrainedNewBuilder[A : Ev]: Builder[A, CC[A]]
6483

65-
implicit def canBuild[E : Ev]: CanBuild[E, CC[E]] = new CanBuild[E, CC[E]] {
66-
def fromIterable(it: Iterable[E]): CC[E] = constrainedFromIterable[E](it)
67-
def newBuilder: Builder[E, CC[E]] = constrainedNewBuilder[E]
84+
implicit def buildFrom[F, E : Ev]: BuildFrom[CC[F], E] { type To[_] <: CC[E] } = new BuildFrom[CC[F], E] {
85+
type To[_] = CC[E]
86+
def fromIterable[X <: E](it: Iterable[X]): CC[E] = constrainedFromIterable[E](it)
87+
def newBuilder[X <: E]: Builder[X, CC[E]] = constrainedNewBuilder[E]
6888
}
89+
90+
def buildFromAny[E : Ev]: BuildFrom[Nothing, E] { type To[_] <: CC[E] } =
91+
buildFrom[Any, E].asInstanceOf[BuildFrom[Nothing, E] { type To[_] <: CC[E] }]
6992
}

src/main/scala/strawman/collection/Map.scala

+17-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package strawman.collection
22

33
import strawman.collection.mutable.Builder
44

5-
import scala.{Option, Any}
5+
import scala.{Option, Any, Nothing}
66
import scala.annotation.unchecked.uncheckedVariance
77
import scala.Predef.???
88

@@ -49,13 +49,17 @@ trait MapFactory[+C[_, _]] extends BuildConstrained { self =>
4949
def apply[K, V](elems: (K, V)*): C[K, V] =
5050
newBuilder[K, V].++=(elems.toStrawman).result
5151

52-
protected[this] lazy val canBuildProto: CanBuild[(Any, Any), C[Any, Any]] = new CanBuild[(Any, Any), C[Any, Any]] {
53-
def fromIterable(it: Iterable[(Any, Any)]): C[Any, Any] = self.fromIterable[Any, Any](it)
54-
def newBuilder: Builder[(Any, Any), C[Any, Any]] = self.newBuilder[Any, Any]
52+
protected[this] lazy val buildFromProto: BuildFrom[C[Any, Any], (Any, Any)] { type To[_] <: C[Any, Any] } = new BuildFrom[C[Any, Any], (Any, Any)] {
53+
type To[_] = C[Any, Any]
54+
def fromIterable[E <: (Any, Any)](it: Iterable[E]): C[Any, Any] = self.fromIterable[Any, Any](it)
55+
def newBuilder[E <: (Any, Any)]: Builder[E, C[Any, Any]] = self.newBuilder[Any, Any]
5556
}
5657

57-
implicit def canBuild[K, V]: CanBuild[(K, V), C[K, V]] =
58-
canBuildProto.asInstanceOf[CanBuild[(K, V), C[K, V]]]
58+
implicit def buildFrom[K2, V2, K, V]: BuildFrom[C[K2, V2], (K, V)] { type To[_] <: C[K, V] } =
59+
buildFromProto.asInstanceOf[BuildFrom[C[K2, V2], (K, V)] { type To[_] <: C[K, V] }]
60+
61+
def buildFromAny[K, V]: BuildFrom[Nothing, (K, V)] { type To[_] <: C[K, V] } =
62+
buildFrom[Any, Any, K, V].asInstanceOf[BuildFrom[Nothing, (K, V)] { type To[_] <: C[K, V] }]
5963
}
6064

6165
/** Factory methods for collections of kind `* −> * -> *` which require an implicit evidence value for the key type */
@@ -72,8 +76,12 @@ trait ConstrainedMapFactory[+C[_, _], Ev[_]] { self =>
7276
def apply[K : Ev, V](elems: (K, V)*): C[K, V] =
7377
constrainedNewBuilder[K, V].++=(elems.toStrawman).result
7478

75-
implicit def canBuild[K : Ev, V]: CanBuild[(K, V), C[K, V]] = new CanBuild[(K, V), C[K, V]] {
76-
def fromIterable(it: Iterable[(K, V)]): C[K, V] = self.constrainedFromIterable(it)
77-
def newBuilder: Builder[(K, V), C[K, V]] = self.constrainedNewBuilder
79+
implicit def buildFrom[K2, V2, K : Ev, V]: BuildFrom[C[K2, V2], (K, V)] { type To[_] <: C[K, V] } = new BuildFrom[C[K2, V2], (K, V)] {
80+
type To[_] = C[K, V]
81+
def fromIterable[E <: (K, V)](it: Iterable[E]): C[K, V] = self.constrainedFromIterable(it)
82+
def newBuilder[E <: (K, V)]: Builder[E, C[K, V]] = self.constrainedNewBuilder
7883
}
84+
85+
def buildFromAny[K : Ev, V]: BuildFrom[Nothing, (K, V)] { type To[_] <: C[K, V] } =
86+
buildFrom[Any, Any, K, V].asInstanceOf[BuildFrom[Nothing, (K, V)] { type To[_] <: C[K, V] }]
7987
}

src/test/scala/strawman/collection/test/TraverseTest.scala

+8-8
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ import java.lang.String
1313

1414
class TraverseTest {
1515

16-
def optionSequence[C[X] <: Iterable[X], A](xs: C[Option[A]])(implicit fi: CanBuild[A, C[A]]): Option[C[A]] =
17-
xs.foldLeft[Option[Builder[A, C[A]]]](Some(fi.newBuilder)) {
16+
def optionSequence[C[X] <: Iterable[X], A](xs: C[Option[A]])(implicit bf: BuildFrom[C[_], A]): Option[bf.To[A]] =
17+
xs.foldLeft[Option[Builder[A, bf.To[A]]]](Some(bf.newBuilder)) {
1818
case (Some(builder), Some(a)) => Some(builder += a)
1919
case _ => None
2020
}.map(_.result)
2121

22-
def eitherSequence[C[X] <: Iterable[X], A, B](xs: C[Either[A, B]])(implicit fi: CanBuild[B, C[B]]): Either[A, C[B]] =
23-
xs.foldLeft[Either[A, Builder[B, C[B]]]](Right(fi.newBuilder)) {
22+
def eitherSequence[C[X] <: Iterable[X], A, B](xs: C[Either[A, B]])(implicit bf: BuildFrom[C[_], B]): Either[A, bf.To[B]] =
23+
xs.foldLeft[Either[A, Builder[B, bf.To[B]]]](Right(bf.newBuilder)) {
2424
case (Right(builder), Right(b)) => Right(builder += b)
2525
case (Left(a) , _) => Left(a)
2626
case (_ , Left(a)) => Left(a)
@@ -41,10 +41,10 @@ class TraverseTest {
4141
val e1 = eitherSequence(xs3)
4242
val e1t: Either[Int, mutable.ListBuffer[String]] = e1
4343

44-
// This use case from https://github.com/scala/scala/pull/5233 still eludes us
45-
//val xs4 = immutable.List((1 -> "a"), (2 -> "b"))
46-
//val o4 = optionSequence(xs1)(immutable.TreeMap.iterableFactory)
47-
//val o4t: Option[immutable.TreeMap[Int, String]] = o4
44+
// Breakout-like use case from https://github.com/scala/scala/pull/5233:
45+
val xs4 = immutable.List[Option[(Int, String)]](Some((1 -> "a")), Some((2 -> "b")))
46+
val o4 = optionSequence(xs4)(immutable.TreeMap.buildFromAny)
47+
val o4t: Option[immutable.TreeMap[Int, String]] = o4
4848
}
4949

5050
}

0 commit comments

Comments
 (0)