-
Notifications
You must be signed in to change notification settings - Fork 70
Implicit builders on top of #110 #112
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package strawman.collection | ||
|
||
import strawman.collection.mutable.Builder | ||
|
||
import scala.{Any, Ordering} | ||
|
||
/** | ||
* Auxiliary type allowing us to define which collection type to build according to the type of an existing collection. | ||
* | ||
* @tparam From Existing collection type that will drives the collection type to build | ||
* @tparam A Element type | ||
*/ | ||
trait BuildFrom[-From, -A] { | ||
|
||
/** Collection type to build */ | ||
type To | ||
|
||
def newBuilder(): Builder[A, To] | ||
|
||
} | ||
|
||
trait BuildFromLowPriority { | ||
|
||
/** | ||
* Extracts the binary type constructor of `From` and applies it to `A` and `B` | ||
* to build the `To` type. | ||
*/ | ||
implicit def binaryTC[CC[_, _], A, B](implicit | ||
cb: CanBuild[(A, B), CC[A, B]] | ||
): BuildFrom.Aux[CC[_, _], (A, B), CC[A, B]] = | ||
new BuildFrom[CC[_, _], (A, B)] { | ||
type To = CC[A, B] | ||
def newBuilder(): Builder[(A, B), CC[A, B]] = cb.newBuilder() | ||
} | ||
|
||
} | ||
|
||
object BuildFrom extends BuildFromLowPriority { | ||
|
||
type Aux[From, A, To0] = BuildFrom[From, A] { type To = To0 } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't collide with Shapeless' name here. The type signature is consistent with something called some variant on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This type makes things really confusing. Can we get rid of it and use either type members or type parameters everywhere? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree. According to the context it can be more convenient to use type members or type parameters. That’s why this pattern is so prevalent in shapeless. I can find a better name than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. I would try to use parameters everywhere because that's how we started. Also, if we bring back CanBuildFrom in a way, it's best not to do arbitrary changes to it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The whole thing looks still very complex to me. Let's see whether we can simplify by going to all parameters. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
|
||
/** | ||
* Extracts the unary type constructor of `From` and applies it to `A` | ||
* to build the `To` type. | ||
*/ | ||
implicit def unaryTC[CC[_], A](implicit | ||
cb: CanBuild[A, CC[A]] | ||
): BuildFrom.Aux[CC[_], A, CC[A]] = | ||
new BuildFrom[CC[_], A] { | ||
type To = CC[A] | ||
def newBuilder(): Builder[A, CC[A]] = cb.newBuilder() | ||
} | ||
|
||
// Explicit BuildFrom instances allowing breakOut-like style (see the tests for usage examples) | ||
// We have to define four variants to support all the combinations of factories (unary vs binary type | ||
// constructor, ordered vs unordered) | ||
|
||
def factory[CC[_], A](iterableFactory: IterableFactoryWithBuilder[CC]): BuildFrom.Aux[Any, A, CC[A]] = | ||
new BuildFrom[Any, A] { | ||
type To = CC[A] | ||
def newBuilder(): Builder[A, CC[A]] = iterableFactory.newBuilder[A]() | ||
} | ||
|
||
def factory[CC[_], A](sortedIterableFactory: SortedIterableFactoryWithBuilder[CC])(implicit ordering: Ordering[A]): BuildFrom.Aux[Any, A, CC[A]] = | ||
new BuildFrom[Any, A] { | ||
type To = CC[A] | ||
def newBuilder(): Builder[A, CC[A]] = sortedIterableFactory.newBuilder[A]() | ||
} | ||
|
||
def factory[CC[X, Y] <: Map[X, Y] with MapOps[X, Y, CC, _], K, V]( | ||
mapFactory: MapFactoryWithBuilder[CC] | ||
): BuildFrom.Aux[Any, (K, V), CC[K, V]] = | ||
new BuildFrom[Any, (K, V)] { | ||
type To = CC[K, V] | ||
def newBuilder(): Builder[(K, V), CC[K, V]] = mapFactory.newBuilder[K, V]() | ||
} | ||
|
||
def factory[CC[X, Y] <: SortedMap[X, Y] with SortedMapOps[X, Y, CC, _], K, V]( | ||
sortedMapFactory: SortedMapFactoryWithBuilder[CC] | ||
)(implicit | ||
ordering: Ordering[K] | ||
): BuildFrom.Aux[Any, (K, V), CC[K, V]] = | ||
new BuildFrom[Any, (K, V)] { | ||
type To = CC[K, V] | ||
def newBuilder(): Builder[(K, V), CC[K, V]] = sortedMapFactory.newBuilder[K, V]() | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package strawman.collection | ||
|
||
import strawman.collection.mutable.Builder | ||
|
||
/** Auxiliary data type used to retrieve the element type `Elem` of a complete collection type `C` */ | ||
trait BuildTo[C] { | ||
|
||
type Elem | ||
|
||
def newBuilder(): Builder[Elem, C] | ||
|
||
} | ||
|
||
object BuildTo { | ||
|
||
/** Provides a `BuildTo` based on an available `CanBuild` for a unary collection type constructor */ | ||
implicit def unaryTC[CC[_], A](implicit cb: CanBuild[A, CC[A]]): BuildTo[CC[A]] { type Elem = A } = | ||
new BuildTo[CC[A]] { | ||
type Elem = A | ||
def newBuilder(): Builder[A, CC[A]] = cb.newBuilder() | ||
} | ||
|
||
/** Provides a `BuildTo` based on an available `CanBuild` for a binary collection type constructor */ | ||
implicit def binaryTC[CC[_, _], A, B](implicit cb: CanBuild[(A, B), CC[A, B]]): BuildTo[CC[A, B]] { type Elem = (A, B) } = | ||
new BuildTo[CC[A, B]] { | ||
type Elem = (A, B) | ||
def newBuilder(): Builder[(A, B), CC[A, B]] = cb.newBuilder() | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could avoid copying if the size matches. We may also consider passing a size hint to
newSpecificBuilder
(but it's probably not as useful in the new design where most operations usefromSpecificIterable
instead).