Skip to content

Instantly share code, notes, and snippets.

@lrytz
Last active May 25, 2021 13:50
Show Gist options
  • Save lrytz/9e1f120c3e93ef50c93ed78b301d72fe to your computer and use it in GitHub Desktop.
Save lrytz/9e1f120c3e93ef50c93ed78b301d72fe to your computer and use it in GitHub Desktop.
object Scala2 {
type Service[K <: Common.AbstractServiceKey[_]] = K#Protocol // error in 3: "K is not a legal path since it is not a concrete type"
}
// object Scala3 {
// type Service[K <: Common.AbstractServiceKey[_]] = K match {
// case Common.AbstractServiceKey[t] => t
// }
// }
object Common {
abstract class AbstractServiceKey[P] {
type Protocol = P
}
type Service[K <: AbstractServiceKey[_]] = Scala2.Service[K]
// type Service[K <: AbstractServiceKey[_]] = Scala3.Service[K]
val m = TypedMultiMap.empty[AbstractServiceKey[_], Service]
}
class TypedMultiMap[T <: AnyRef, K[_ <: T]] private (private val map: Map[T, Set[Any]]) {
def keySet: Set[T] = map.keySet
def inserted(key: T)(value: K[key.type]): TypedMultiMap[T, K] = {
val set = map.get(key) match {
case Some(s) => s
case None => Set.empty[Any]
}
new TypedMultiMap[T, K](map.updated(key, set + value))
}
def get(key: T): Set[K[key.type]] =
map.get(key) match {
case Some(s) => s.asInstanceOf[Set[K[key.type]]]
case None => Set.empty
}
def valueRemoved(value: Any): TypedMultiMap[T, K] = {
val s = Set(value)
val m = map.collect {
case (k, set) if set != s => (k, set - value)
}
new TypedMultiMap[T, K](m)
}
def keyRemoved(key: T): TypedMultiMap[T, K] = new TypedMultiMap[T, K](map - key)
def removed(key: T)(value: K[key.type]): TypedMultiMap[T, K] = {
map.get(key) match {
case None => this
case Some(set) =>
if (set(value)) {
val newset = set - value
val newmap = if (newset.isEmpty) map - key else map.updated(key, newset)
new TypedMultiMap[T, K](newmap)
} else this
}
}
def setAll(key: T)(values: Set[K[key.type]]): TypedMultiMap[T, K] =
new TypedMultiMap[T, K](map.updated(key, values.asInstanceOf[Set[Any]]))
def ++(other: TypedMultiMap[T, K]): TypedMultiMap[T, K] =
new TypedMultiMap[T, K](map ++ other.map)
override def toString: String = s"TypedMultiMap($map)"
override def equals(other: Any) = other match {
case o: TypedMultiMap[_, _] => map == o.map
case _ => false
}
override def hashCode: Int = map.hashCode
}
object TypedMultiMap {
private val _empty = new TypedMultiMap[Nothing, Nothing](Map.empty)
def empty[T <: AnyRef, K[_ <: T]]: TypedMultiMap[T, K] = _empty.asInstanceOf[TypedMultiMap[T, K]]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment