This repository was archived by the owner on Dec 22, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 72
Introduce typeclasses making it easier to write generic extension methods #478
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
6ec4813
Introduce HasSeqOps
julienrf 8cf2b04
Preserve more type information
julienrf 7f1e0e0
Use a class with a type parameter instead of a trait with an abstract…
julienrf b7a0d25
Use BuildFrom to infer a more precise result type
julienrf a8ce058
Introduce HasImmutableMapOps
julienrf e3478c4
Introduce HasIterableOps
julienrf fbc26d8
Add HasMapOps, and make HasXxxOps types a hierarchy so that instances…
julienrf 5d27e4e
Move HasXxxOps traits into the collections-contrib module
julienrf 4538908
Fix code style
julienrf 9af7f4e
Remove type members representing collection types
julienrf 9319353
Turn `val conversion` into `def apply`
julienrf f487dc2
Wrap arrays in ImmutableArray
julienrf File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
43 changes: 43 additions & 0 deletions
43
collections-contrib/src/main/scala/strawman/collection/decorators/HasImmutableMapOps.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package strawman.collection | ||
package decorators | ||
|
||
/** | ||
* Type class witnessing that a collection type `C` has | ||
* a conversion to `immutable.MapOps[K, V, _, _]`. | ||
* | ||
* @see [[scala.collection.decorators.HasIterableOps]] | ||
*/ | ||
trait HasImmutableMapOps[C] extends HasMapOps[C] { | ||
|
||
// Convenient intermediate type definitions to satisfy type bounds | ||
protected type _CC[X, +Y] <: immutable.MapOps[X, Y, _CC, _] | ||
protected type _C <: immutable.MapOps[K, V, _CC, _C] | ||
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. Again, if the user needs to interact with this it should have a better name, e.g. |
||
|
||
/** A conversion from the type `C` to `immutable.MapOps[K, V, _, _]` */ | ||
def apply(c: C): immutable.MapOps[K, V, _CC, _C] | ||
|
||
} | ||
|
||
object HasImmutableMapOps { | ||
|
||
// 1. Map collections | ||
implicit def mapHasMapOps[CC[X, +Y] <: immutable.MapOps[X, Y, CC, CC[X, Y]], K0, V0]: HasImmutableMapOps[CC[K0, V0]] { type K = K0; type V = V0 } = | ||
new HasImmutableMapOps[CC[K0, V0]] { | ||
type K = K0 | ||
type V = V0 | ||
type _CC[X, +Y] = CC[X, Y] | ||
type _C = CC[K, V] | ||
def apply(c: CC[K0, V0]): immutable.MapOps[K0, V0, _CC, _C] = c | ||
} | ||
|
||
// 2. Sorted Map collections | ||
implicit def sortedMapHasMapOps[CC[X, +Y] <: immutable.Map[X, Y] with immutable.SortedMapOps[X, Y, CC, CC[X, Y]], K0, V0]: HasImmutableMapOps[CC[K0, V0]] { type K = K0; type V = V0 } = | ||
new HasImmutableMapOps[CC[K0, V0]] { | ||
type K = K0 | ||
type V = V0 | ||
type _CC[X, +Y] = immutable.Map[X, Y] | ||
type _C = _CC[K, V] | ||
def apply(c: CC[K0, V0]): immutable.MapOps[K0, V0, _CC, _C] = c | ||
} | ||
|
||
} |
44 changes: 44 additions & 0 deletions
44
collections-contrib/src/main/scala/strawman/collection/decorators/HasIterableOps.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package strawman.collection | ||
package decorators | ||
|
||
/** | ||
* Type class witnessing that a collection type `C` | ||
* has elements of type `A` and has a conversion to `IterableOps[A, _, _]`. | ||
* | ||
* This type enables simple enrichment of `Iterable`s with extension methods. | ||
* | ||
* @tparam C Collection type (e.g. `List[Int]`) | ||
*/ | ||
trait HasIterableOps[C] { | ||
|
||
/** The type of elements (e.g. `Int`) */ | ||
type A | ||
|
||
/** A conversion from the type `C` to `IterableOps[A, _, _]` */ | ||
def apply(c: C): IterableOps[A, AnyConstr, _] | ||
|
||
} | ||
|
||
object HasIterableOps extends LowPriorityHasIterableOps { | ||
|
||
implicit def iterableHasIterableOps[CC[X] <: IterableOps[X, AnyConstr, _], A0]: HasIterableOps[CC[A0]] { type A = A0 } = | ||
new HasIterableOps[CC[A0]] { | ||
type A = A0 | ||
def apply(c: CC[A0]): IterableOps[A0, AnyConstr, _] = c | ||
} | ||
|
||
} | ||
|
||
trait LowPriorityHasIterableOps { | ||
|
||
// Makes `HasSeqOps` instances visible in `HasIterableOps` companion | ||
implicit def hasSeqOpsHasIterableOps[C, A0](implicit | ||
hasSeqOps: HasSeqOps[C] { type A = A0 } | ||
): HasIterableOps[C] { type A = A0 } = hasSeqOps | ||
|
||
// Makes `HasMapOps` instances visible in `HasIterableOps` companion | ||
implicit def hasMapOpsHasIterableOps[C, K0, V0](implicit | ||
hasMapOps: HasMapOps[C] { type K = K0; type V = V0 } | ||
): HasIterableOps[C] { type A = (K0, V0) } = hasMapOps | ||
|
||
} |
46 changes: 46 additions & 0 deletions
46
collections-contrib/src/main/scala/strawman/collection/decorators/HasMapOps.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package strawman.collection | ||
package decorators | ||
|
||
/** | ||
* Type class witnessing that a collection type `C` | ||
* has keys of type `K`, values of type `V` and has a conversion to `MapOps[K, V, _, _]`. | ||
* | ||
* This type enables simple enrichment of `Map`s with extension methods. | ||
* | ||
* @tparam C Collection type (e.g. `Map[Int, String]`) | ||
*/ | ||
trait HasMapOps[C] extends HasIterableOps[C] { | ||
|
||
/** The type of keys */ | ||
type K | ||
|
||
/** The type of values */ | ||
type V | ||
|
||
type A = (K, V) | ||
|
||
/** A conversion from the type `C` to `MapOps[K, V, _, _]` */ | ||
def apply(c: C): MapOps[K, V, ({ type l[X, +Y] = IterableOps[_, AnyConstr, _] })#l, _] | ||
|
||
} | ||
|
||
object HasMapOps extends LowPriorityHasMapOps { | ||
|
||
// 1. Map collections | ||
implicit def mapHasMapOps[CC[X, +Y] <: MapOps[X, Y, ({ type l[X, +Y] = IterableOps[_, AnyConstr, _] })#l, _], K0, V0]: HasMapOps[CC[K0, V0]] { type K = K0; type V = V0 } = | ||
new HasMapOps[CC[K0, V0]] { | ||
type K = K0 | ||
type V = V0 | ||
def apply(c: CC[K0, V0]): MapOps[K0, V0, ({ type l[X, +Y] = IterableOps[_, AnyConstr, _] })#l, _] = c | ||
} | ||
|
||
} | ||
|
||
trait LowPriorityHasMapOps { | ||
|
||
// Makes `HasImmutableMapOps` instances visible in `HasMapOps` companion | ||
implicit def hasImmutableMapOpsHasMapOps[C, K0, V0](implicit | ||
hasImmutableMapOps: HasImmutableMapOps[C] { type K = K0; type V = V0 } | ||
): HasMapOps[C] { type K = K0; type V = V0 } = hasImmutableMapOps | ||
|
||
} |
60 changes: 60 additions & 0 deletions
60
collections-contrib/src/main/scala/strawman/collection/decorators/HasSeqOps.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package strawman.collection | ||
package decorators | ||
|
||
import scala.{Array, Char, Int} | ||
import scala.Predef.String | ||
import strawman.collection.immutable.{ImmutableArray, Range} | ||
|
||
/** Type class witnessing that a collection type `C` has | ||
* elements of type `A` and has a conversion to `SeqOps[A, _, _]`. | ||
* | ||
* This type enables simple enrichment of `Seq`s with extension methods which | ||
* can make full use of the mechanics of the Scala collections framework in | ||
* their implementation. | ||
* | ||
* @see [[scala.collection.decorators.HasIterableOps]] | ||
*/ | ||
trait HasSeqOps[C] extends HasIterableOps[C] { | ||
/** A conversion from the type `C` to `SeqOps[A, _, _]`. */ | ||
def apply(c: C): SeqOps[A, AnyConstr, _] | ||
} | ||
|
||
object HasSeqOps { | ||
|
||
// we want to provide implicit instances that unify all possible types `X` with a `SeqOps[A, CC, C]` | ||
// 1. Seq collections | ||
implicit def seqHasSeqOps[CC[X] <: SeqOps[X, AnyConstr, _], A0]: HasSeqOps[CC[A0]] {type A = A0 } = | ||
new HasSeqOps[CC[A0]] { | ||
type A = A0 | ||
def apply(c: CC[A0]): SeqOps[A0, AnyConstr, _] = c | ||
} | ||
|
||
// 2. String | ||
implicit def stringHasSeqOps: HasSeqOps[String] { type A = Char } = | ||
new HasSeqOps[String] { | ||
type A = Char | ||
def apply(c: String): SeqOps[Char, AnyConstr, _] = stringToStringOps(c) | ||
} | ||
|
||
// 3. StringView | ||
implicit def stringViewHasSeqOps: HasSeqOps[StringView] { type A = Char } = | ||
new HasSeqOps[StringView] { | ||
type A = Char | ||
def apply(c: StringView): SeqOps[Char, AnyConstr, _] = c | ||
} | ||
|
||
// 4. Array | ||
implicit def arrayHasSeqOps[A0]: HasSeqOps[Array[A0]] { type A = A0 } = | ||
new HasSeqOps[Array[A0]] { | ||
type A = A0 | ||
def apply(c: Array[A0]): SeqOps[A0, AnyConstr, _] = ImmutableArray.unsafeWrapArray(c) | ||
} | ||
|
||
// 5. Range collections | ||
implicit def rangeHasSeqOps[C <: Range]: HasSeqOps[C] { type A = Int } = | ||
new HasSeqOps[C] { | ||
type A = Int | ||
def apply(c: C): SeqOps[Int, AnyConstr, _] = c | ||
} | ||
|
||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
If the user ever needs to interact with this type directly, I would change the name to something more memorable, e.g.
MapOf
.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 is an implementation detail which is not supposed to be used by users. I wish I could get rid of it but couldn’t figure out how.