-
Notifications
You must be signed in to change notification settings - Fork 72
Make the different kinds of collection companions consistent together #36
Conversation
…. Define an implicit CanBuild that can be used by end-users to retrieve a factory for a given collection type.
} | ||
|
||
/** Base trait for builder factories */ | ||
trait CanBuild[-A, +Repr] { |
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.
Do we gain anything from this beyond just having the type be () => Builder[A, C[A]]
?
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.
I find a little bit nicer to have implicit vals of type CanBuild[…]
rather than () => Builder[…]
. I find it also a little bit nicer to take parameters of type CanBuild[…]
rather than () => Builder[…]
. This is a matter of taste…
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.
Okay, but in the former case we'd need only
implicit def canBuild[A] = () => newBuilder[A, C[A]]
instead of the four lines we have now.
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.
Alright, I was reluctant to define implicit vals with type Function1
because they can act as implicit conversions, but in the case the type () => _
the corresponding type is Function0
so it’s perfectly fine.
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.
Actually, I’m thinking that CanBuild
also has the following advantages:
- Simpler to use for end-users (e.g. the type of the parameter is
CanBuild[A, C[A]]
instead of() => Builder[A, C[A]]
) ; - We could add other methods than just
apply(): Builder[A, C[A]]
, likeapply(knownSize: Int): Builder[A, C[A]]
.
I'm not convinced by this object List extends CollectionCompanion[List] {
implicit val companion: CollectionCompanion[List] = this
} This provides convenient access to both, The limitation to unary type constructors isn't particularly nice. This would be better (if we don't run into any variance problems; I haven't tried it): object List extends CollectionCompanion[List[Any]] {
implicit def companion[T]: CollectionCompanion[List[T]] = this
}
object HashMap extends CollectionCompanion[HashMap[Any, Nothing]] {
implicit def companion[K, V]: CollectionCompanion[HashMap[K, V]] =
this // may require cast or @uncheckedVariance
} |
Small addition: It doesn't fully cover constrained collections that require more than a type evidence. We can safely cast if variance is an issue but for |
Continuing this line of thought, constrained collections cannot implement |
Something to keep in mind: scala/scala#5233 Rather than "allow me to build whatever I want" the essence of this seems to be "make it work for Maps". It would be nice to get this right by default, which requires moving away from any design that requires a unary type constructor. (The "allow me to build whatever" case can be covered by Views) |
} | ||
|
||
/** Base trait for companion objects of collections */ | ||
trait IterableFactories[+C[X] <: Iterable[X]] extends FromIterable[C] { |
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.
Why was this renamed from IterableFactory
to IterableFactories
?
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.
I thought it would make more sense because this trait provides several factory methods. We can just settle on either XxxFactory
or XxxFactories
…
I also think Factory is the established wording, whether there are several
methods or not.
…On Mon, Mar 6, 2017 at 7:01 PM, Julien Richard-Foy ***@***.*** > wrote:
***@***.**** commented on this pull request.
------------------------------
In src/main/scala/strawman/collection/IterableFactories.scala
<#36 (comment)>
:
> @@ -0,0 +1,26 @@
+package strawman
+package collection
+
+import strawman.collection.mutable.Builder
+
+import scala.Int
+
+/** Base trait for instances that can construct a collection from an iterable */
+trait FromIterable[+C[X] <: Iterable[X]] {
+ def fromIterable[B](it: Iterable[B]): C[B]
+}
+
+/** Base trait for companion objects of collections */
+trait IterableFactories[+C[X] <: Iterable[X]] extends FromIterable[C] {
I thought it would make more sense because this trait provides several
factory methods. We can just settle on either XxxFactory or XxxFactories…
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#36 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAwlVu8BEiqWHKlNMiQSpkuTnFy4unqzks5rjEn_gaJpZM4MLOwY>
.
--
Martin Odersky
EPFL and Lightbend
|
``` ⚡ scala Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_162). Type in expressions for evaluation. Or try :help. scala> class OfDim { Array.ofDim[Any](32) } defined class OfDim scala> :javap -c OfDim Compiled from "<console>" public class $line3.$read$$iw$$iw$OfDim { public $line3.$read$$iw$$iw$OfDim(); Code: 0: aload_0 1: invokespecial scala#17 // Method java/lang/Object."<init>":()V 4: getstatic scala#23 // Field scala/Array$.MODULE$:Lscala/Array$; 7: bipush 32 9: getstatic scala#28 // Field scala/reflect/ClassTag$.MODULE$:Lscala/reflect/ClassTag$; 12: invokevirtual scala#32 // Method scala/reflect/ClassTag$.Any:()Lscala/reflect/ClassTag; 15: invokevirtual scala#36 // Method scala/Array$.ofDim:(ILscala/reflect/ClassTag;)Ljava/lang/Object; 18: pop 19: return } scala> class NewArray { new Array[Object](32) } defined class NewArray scala> :javap -c NewArray Compiled from "<console>" public class $line4.$read$$iw$$iw$NewArray { public $line4.$read$$iw$$iw$NewArray(); Code: 0: aload_0 1: invokespecial scala#17 // Method java/lang/Object."<init>":()V 4: bipush 32 6: anewarray scala#4 // class java/lang/Object 9: pop 10: return } ```
Also, define an implicit builder factory
() => Builder[A, C[A]]
that can be used by end-users to retrieve a factory for a given collection type. For instance we can now writeFuture.sequence
(or equivalent) as follows:Note that I duplicated the collection factories:
IterableFactory
works only for collection types of kind* -> *
,OrderingGuidedFactory
works for the same kind of collection types but requires an implicitOrdering
,MapFactory
works for collection types of kind* -> * -> *
, andSortedMapFactory
is the same but requires an implicitOrdering
for keys. I don’t think this duplication is a problem. Trying to abstract over these difference would not be worth it, in my opinion.