datastructure that holds closures, parametrically in scala - scala

I am implementing a GUI event system in Scala. I have something like:
case class EventObject
case class KeyEventObject extends EventObject
case class MouseEventObject extends EventObject
I would like to store event listener closures in a (multi-)map, like so:
var eventListeners = new MultiMap[EventDescriptor, (EventObject => Unit)];
My question is, is there some way to rewrite this so that the function signatures of the stored closure can be EventObject or any subclass? Something like the following:
var eventListeners = new MultiMap[EventDescriptor, [A <: EventObject](A => Unit)]
so that I can have the subtype known when I define the listener functions:
eventListeners.put(KEY_EVENT, (e:KeyEventObject) => { ... })
eventListeners.put(MOUSE_EVENT, (e:MouseEventObject) => { ... })

Not that many things are impossible. You can do the following, for example, with type classes:
class HMultiMap {
import scala.collection.mutable.{ Buffer, HashMap }
type Mapping[K, V]
private[this] val underlying = new HashMap[Any, Buffer[Any]]
def apply[K, V](key: K)(implicit ev: Mapping[K, V]) =
underlying.getOrElse(key, Buffer.empty).toList.asInstanceOf[List[V]]
def add[K, V](key: K)(v: V)(implicit ev: Mapping[K, V]) = {
underlying.getOrElseUpdate(key, Buffer.empty) += v
this
}
}
And now:
sealed trait EventObject
case class KeyEventObject(c: Char) extends EventObject
case class MouseEventObject(x: Int, y: Int) extends EventObject
sealed trait EventDescriptor
case object KEY_EVENT extends EventDescriptor
case object MOUSE_EVENT extends EventDescriptor
class EventMap extends HMultiMap {
class Mapping[K, V]
object Mapping {
implicit object k extends Mapping[KEY_EVENT.type, KeyEventObject => Unit]
implicit object m extends Mapping[MOUSE_EVENT.type, MouseEventObject => Unit]
}
}
It's a little messy, but the usage is much prettier:
val eventListeners = new EventMap
eventListeners.add(KEY_EVENT)((e: KeyEventObject) => println(e.c))
eventListeners.add(MOUSE_EVENT)((e: MouseEventObject) => println("X: " + e.x))
eventListeners.add(KEY_EVENT)((e: KeyEventObject) => println(e.c + " again"))
We can confirm that we can pick out individual kinds of event handlers:
scala> eventListeners(KEY_EVENT).size
res3: Int = 2
And we can pretend to fire an event and run all the handlers for it:
scala> eventListeners(KEY_EVENT).foreach(_(KeyEventObject('a')))
a
a again
And it's all perfectly safe, since nothing gets into the underlying loosely-typed map without the proper evidence. We'd get a compile-time error if we tried to add a function from String to Unit, for example.

EDIT
Seems impossible. Also a case-to-case inheritance gets prohibited in Scala-2.10
...
Maybe by using some specific trait and declaring event object classes sealed and extend that trait?
val eventListeners = new MultiMap[EventDescriptor, ((_ >: EventTrait) => Unit)]
From List sources:
:+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That
That - is a specific type, it could be built from your EventTrait by implicit builder, one builder for each event type. Instead of elem: B try use classOf[B]. Create get methods that will access your MultiMap using different classOf:
def getMouseEvent(ed: EventDescriptor) = multimap.entrySet.filter(
(a, b) => a == ed ).map((a, b) => (a, convertTo(ClassOf[MouseEvent], b)).
filter((a, b) => b != null)
convertTo returns null if it could not convert event to appropriate type
Ugly.

It's impossible.
Let's suppose you have such Map:
val f = eventListeners(key).head
How would you call the function f? With parameter of type EventObject? You can't. It could be KeyEventObject => Unit. With parameter of type KeyEventObject? You can't. It could be MouseEventObject => Unit.
You can use PartialFunction[EventObject, Unit] and check for isDefinedAt every time, but it's an ugly way.

Related

How to chain generically chain functions returning Either with an operator like `andThen`?

Problem: Chaining multiple Either returning functions, the Left of which are all failures inheriting from a common sealed trait InternalError. However, the compiler complains that the chain is returning Either[_,Success] instead of Either[InternalError, Success].
Here's the code that does the chaining:
import scala.language.implicitConversions
object EitherExtension {
implicit class AndThenEither[A,B](val e: Function1[A,Either[_,B]]) {
//get ability to chain/compose functions that return aligning Eithers
def andThenE[C](f:Function1[B, Either[_,C]]): Function1[A, Either[_,C]] = {
(v1: A) => e.apply(v1).flatMap(b => f.apply(b))
}
}
}
As was pointed out in the comments this discards the type of Left. If I change it the below it will not work since the final output can be of type Either[X|Y, C] which resolves to Either[_,C] and I'm back to square one.
implicit class AndThenEither[A,B,X](val e: (A) => Either[X, B]) {
def andThenE[C,Y](f:(B) => Either[Y, C]): (A) => Either[_, C] = {
(v1: A) => e.apply(v1).flatMap(b => f.apply(b))
}
}
Here's the example showing the compositional failure of type alignment:
import EitherExtension._
object AndThenComposition {
//sample type definitions of failure responses
sealed trait InternalError
case class Failure1() extends InternalError
case class Failure2() extends InternalError
//sample type definitions
case class Id(id: Int)
case class Stuff()
//sample type definitions of successful responses
case class Output1()
case class Output2()
case class InputRequest()
val function1: (InputRequest) => Either[Failure1, Output1] = ???
val function2: (Output1) => Either[Failure2, Output2] = ???
def doSomething(s:Id, l:List[Stuff]): Either[InternalError, Output2] = {
val pipeline = function1 andThenE function2
pipeline(InputRequest()) //Why is this of type Either[_, Output2]
}
}
What am I missing? How can I get the return type to not be Either[Any, Output2] but rather the base/sealed trait? Is this possible to do generically?
You need to preserve the type of the left so we will modify the extension method to do that.
Note that, since both eithers can have different left types, what we will do is use a type bound to ask the compiler to infer the LUB between those types; thanks to Any this is always possibles (although not always helpful).
object EitherExtension {
implicit class AndThenEither[I, L1, R1](private val f: I => Either[L1, R1]) extends AnyVal {
def andThenE[L2 >: L1, R2](g: R1 => Either[L2, R2]): I => Either[L2, R2] =
i => f(i).flatMap(g)
}
}
Which can be used like this:
import EitherExtension._
object AndThenComposition {
sealed trait InternalError
final case object Failure1 extends InternalError
final case object Failure2 extends InternalError
val function1: Int => Either[Failure1.type, String] = ???
val function2: String => Either[Failure2.type, Boolean] = ???
def doSomething(input: Int): Either[InternalError, Boolean] = {
(function1 andThenE function2)(input)
}
}
See the code running here.
In case you're using this in production, and it's not just a learning thing, what you're looking for it's called Kleisli, and fortunately cats-core already implements it.
According to the cats-core docs:
Kleisli enables composition of functions that return a monadic value,
for instance an Option[Int] or a Either[String, List[Double]], without
having functions take an Option or Either as a parameter, which can be
strange and unwieldy.
Since Kleisli composes two functions with the signature A => F[B], you'd need only one abstraction to be able to use Kleisli, which is creating a new type for your operation:
type Operation[A] = Either[InternalFailure, A]
By doing this, you should be able to use Kleisli like this:
import cats.data.Kleisli
val first: Kleisli[Operation, InputRequest, Output1] = Kleisli { request: InputRequest =>
Left(Failure1())
}
val second: Kleisli[Operation, Output1, Output2] = Kleisli { output: Output1 =>
Right(Output2())
}
val composed = first.andThen(second)

Scala: Generic isInstanceOf based on sealed hierarchy

I'm trying to generalize some sort of isIntanceOf based on a sealed hierarchy, but haven't been successful. The example below demonstrates what I want to achieve:
sealed abstract class Context
object Context {
case object Context1 extends Context
case class Context2(someInfo: String) extends Context
case object Context3 extends Context
}
case class ContextHolder(id: String, contexts: Set[Context])
import Context._
val holder = ContextHolder("1", Set(Context1, Context2("Other info")))
val contains1Or2 = holder.contexts.contains(Context1) || holder.contexts.exists(_.isInstanceOf[Context2])
val contains3 = holder.contexts.contains(Context3)
println(s"contains1Or2: $contains1Or2")
println(s"contains3: $contains3")
Basically I want to generalize the code of contains1Or2 and contains3 in some sort of:
def containsAnyOf[T <: Context: ClassTag](holder: ContextHolder, contexts: T*): Boolean
And then be able to use it like:
val contains1Or2 = containsAnyOf(holder, Context1, Context2)
val contains3 = containsAnyOf(holder, Context3)
I've already tried a few different approaches, but couldn't get it to work so far. Any ideas? Thanks.
The best I could come up was this:
def containsAnyOf(holder: ContextHolder)(contexts: PartialFunction[Context, Unit]): Boolean = {
val p = contexts.lift.andThen(_.isDefined)
holder.contexts.exists(p)
}
Which you can use like this:
val contains1Or2 = containsAnyOf(holder) {
case Context1 =>
case Context2(_) => // or case _: Contaxt2 =>
}
val contains3 = containsAnyOf(holder) {
case Context3 =>
}
Code running here.
Shapeless's LiftAll type class is very handy here.
import shapeless.ops.hlist.{LiftAll, ToTraversable}
import shapeless.{Generic, HList}
final class ContainsMulti[T <: Product](private val dummy: Boolean = true) extends AnyVal {
def apply[H <: HList, O <: HList](holder: ContextHolder)(implicit
toHList: Generic.Aux[T, H],
classTags: LiftAll.Aux[ClassTag, H, O],
allCtxts: LiftAll[({type E[T] = T <:< Context})#E, H],
toList: ToTraversable.Aux[O, List, ClassTag[_]]
) = classTags.instances.toList
.map(_.runtimeClass)
.forall(klazz => holder.contexts.exists(klazz.isInstance))
}
def containsMulti[T <: Product] = new ContainsMulti[T]
Usage:
val contains1Or2 = containsMulti[(Context1.type, Context2)](holder)
val contains3 = containsMulti[Tuple1[Context3.type]](holder)
val contains1and3 = containsMulti[(Context1.type, Context3.type)](holder)
val check = containsMulti[(Int, String)](holder) //doesn't compile
println(s"contains1Or2: $contains1Or2") //true
println(s"contains3: $contains3") //false
println(s"contains1and3: $contains1and3")//false
See it run.
All the implicits may seem daunting, but it's actually very simple. The extra class is so we can take multiple type parameter lists, where the first is explicitly given, and the second is inferred. Generic turns the inputted tuple into an HList, LiftAll finds the ClassTag instances for each of the types in the tuple, and ToTraversable turns the HList containing those class tags back into a List.
As Luis Miguel Mejía Suárez suggested, I have made ContainsMulti a value class, using the partially applied type trick to avoid object creation. They also pointed out that this approach initially allowed (Int, String) as input, so now allCtxts checks that all the types in the HList extend Context.

creating implicit type class instance in generic way for Seq collections

I'm trying to write a generic implicit instance for the following structure :
object SmartHasher {
trait GetSmartHash[T] {
def calculateHash(value: T): Int
}
object syntax {
implicit class GetHashOps[T: GetSmartHash](itemToBeHashed: T) {
def hashItSmartway(implicit GetSmartHashInstance: GetSmartHash[T]): Int =
GetSmartHashInstance.calculateHash(itemToBeHashed)
}
}
object instances {
import syntax._
implicit def stringSmartHash: GetSmartHash[String] = (s: String) =>s.size % 10 // smart demo thing :D
}
Now I'm trying to define a generic implicit instance that works for any Vector, List, Or Array
where smarthash method for its elements are defined
:
What type I shoud use instead of Seq , as Im trying with it and it doesnt work out ?
implicit def sequenceHash[T: GetSmartHash]: GetSmartHash[Seq[T]] =
(sequence: Seq[T]) => sequence.map(element => element.hashItSmartway).product
If I define It for an exact collection like Vector :
implicit def sequenceHash[T: GetSmartHash]: GetSmartHash[Vector[T]] =
(sequence: Vector[T]) => sequence.map(element => element.hashItSmartway).product
then it works as I expected.
Any suggestions to write this in generic way for theese 3 collections, to prevent for repeating simillar code 3 times?
Regards.
Try
object instances {
import syntax._
// stringSmartHash ...
implicit def sequenceHash[Col[X] <: Iterable[X], T: GetSmartHash]: GetSmartHash[Col[T]] =
(sequence: Col[T]) => sequence.map(element => element.hashItSmartway).product
}
Testing:
import instances._, syntax._
List("aa", "bbb").hashItSmartway //6
Seq("aa", "bbb").hashItSmartway //6
Vector("aa", "bbb").hashItSmartway //6
If you want sequenceHash to work also for Array replace upper bound with view bound
implicit def sequenceHash[Col[_], T: GetSmartHash](implicit ev: Col[T] => Iterable[T]): GetSmartHash[Col[T]] =
(sequence: Col[T]) => sequence.map(element => element.hashItSmartway).product

Pattern matching by dynamic type as argument to function

I am playing with scala and I was trying to create a method that would return a list of instances filtered by a given type (passed through parameters of the function):
I tried the following, but it is not even compiling:
trait A
trait B extends A
trait C extends A
case class B1() extends B {}
case class B2() extends B {}
case class C1() extends C {}
case class C2() extends C {}
def filterByType[F <: A](list: List[A], t: Class[F]): List[F] = list flatMap {
case f: F => Some(f)
case _ => None
}
val list: List[A] = List(B1(), B2(), C1(), C2()) // type of A
val filteredList: List[B] = filterByType(list, Class[B]) // This should return a sublist like List(B1(), B2()) and be type of B
println(filteredList)
Is there a way to do something like this in scala? What would be the correct way of doing this?
Thanks!
EDIT:
I have also tried passing classOf[B] with no luck either.
You can do something like this:
(using ClassTag)
trait A
trait B extends A
final case class B1() extends B
final case class B2() extends B
trait C extends A
final case class C1() extends C
final case class C2() extends C
import scala.reflect.ClassTag
def filterByType[F <: A : ClassTag](list: List[A]): List[F] =
list.collect {
case f: F => f
}
Which you can use like this:
val list: List[A] = List(B1(), B2(), C1(), C2())
val filteredList: List[B] = filterByType[B](list)
// filteredList: List[B] = List(B1(), B2())
Note: Due type erasure this has some limitations, but it seems it will work for your use case.
For a more general approach I would create my own typeclass.
With only Class[F] you can do
def filterByType[F <: A](list: List[A], t: Class[F]): List[F] = list flatMap {
case f if t.isInstance(f) => Some(t.cast(f))
case _ => None
}
or shorter but less efficient
def filterByType[F <: A](list: List[A], t: Class[F]): List[F] = list flatMap {
x => Try { t.cast(x) }.toOption
}
As Luis Miguel Mejía Suárez's answer shows, pattern matching has special support for : F is a ClassTag[F] is available, but it doesn't extend to anything else.

How do I compare abstract WeakTypeTag's unrepresented Generics

I need to check the type of any object and get the corresponding object.
However, T can not be resolved by passing it to a normal functional parameter.
You need to compare until all the type parameters match.
trait Wrap[T]
trait Interface
trait InterfaceA extends Interface
trait InterfaceB extends Interface
object InterfaceAImpl extends Wrap[InterfaceA] with Candidate
object InterfaceBImpl extends Wrap[InterfaceB] with Candidate
trait Mediate[T <: Interface] {
val t: T = get[Wrap[T]]
}
object A extends Mediate[InterfaceA]
object B extends Mediate[InterfaceB]
def get[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[Option[T]] = {
import c.universe._
// Find an object that mixes in a specific interface
// Suppose that the result is [[object A]] and [[object B]]
val detected: List[Symbol] = new CandidateExtractor[c.type](c).run[Candidate]
// This result is
// "InterfaceAImpl =:= Wrap[T]"
// "InterfaceBImpl =:= Wrap[T]"
// When called from A, it expects Wrap[InterfaceA] instead of Wrap[T]
detected.foreach(x => println(s"${x.typeSignature} =:= ${weakTypeOf[T]}"))
// Find objects that inherits Wrap [T] among objects that inherit a specific interface
val r = detected.collectFirst {
// Wrap[InterfaceA] and Wrap[T] are compared, so all false.
case x if x.typeSignature =:= weakTypeOf[T] => x
}
c.Expr[Option[T]](
q"$r"
)
}
Is there any way to compare inheritance relationships, including generics?
For second Try
As a result, what I want to do is...
object A's t: T = InterfaceAImpl because it inherits Wrap[InterfaceA]
object B's t: T = InterfaceBImpl because it inherits Wrap[InterfaceB]
So <:<(typeOf[Wrap[_]) is invalid.
Must be <:<(Wrap[_])
and baseClasses.find(Wrap[_]).typeArgs.contains(T (is InterfaceA or InterfaceB))
Try
List(typeOf[Wrap[_]].typeSymbol, typeOf[Candidate].typeSymbol).forall(x.typeSignature.baseClasses.contains)
or
List(typeOf[Wrap[_]].typeSymbol, typeOf[Candidate].typeSymbol).forall(x.typeSignature.baseType(_) match { case _ : TypeRef => true; case NoType => false })