Cast functions in scala - scala

I have the base class Message and two derived classes One and Two. Method regHandler accepts function Message => Message as argument. When i created method handler and passed it to regHandler, it throws cast error.
class Message
class One extends Message
class Two extends Message
type Handler = Message => Message
def regHandler(handler: Handler) {}
def handler(one: One) : Two = {
new Two
}
regHandler(handler) // <- error here
I tried change my code like this:
var f : Handler
def regHandler[T >: Message, R >: Message](handler: T => R) = {
f = handler // <- but cast error here occurred
}
How do i need change my code to make it work ?

There is a very good reason it doesn't work: your Handler definition says it accepts any Message, but handler only accepts One. Kolberg proposes one solution, but the simpler one would be just to fix handler:
def handler(m: Message) = m match {
case one: One => new Two
case _ => // whatever you want to do here
}
You can throw an exception, which would be equivalent to other answers, except you can have a better error message; you can remove the line, which will throw MatchError; you can return Option[Message]; etc.
Now you can assign it, store it in a map, etc. easily:
object Main extends App {
class Message
class One extends Message
class Two extends Message
type Handler = Message => Message
def regHandler(handler: Handler) {}
def handler(m: Message) = m match {
case one: One => new Two
case _ => throw new Exception(s"handler expected One, got $m")
}
regHandler(handler)
val f: Handler = handler // no _ required
val map: Map[String, Handler] = Map("1" -> handler)
}
Or if you really don't want to change method signatures, make Handlers out of them explicitly (it could be an implicit conversion as well, but since it can introduce errors, I don't recommend it):
object Handler {
def apply[A <: Message, B <: Message](f: A => B): Handler = f.asInstanceOf[Handler]
// alternately if you want to handle ClassCastException for wrong argument type
// def apply[A <: Message, B <: Message](f: A => B): Handler =
// x => try { f(x) } catch { case e: ClassCastException => ... }
}
regHandler(Handler(handler))

The type bounds in
def regHandler[T >: Message, R >: Message](handler: T => R) = {
are wrong, because with >: you are telling the compiler that T,R should be super types of Message. I think you want sub types of Message:
def regHandler[T <: Message, T <: Message](handler: T => R) {}
def handler(one: One) : Two = {
new Two
}
regHandler(handler)
works for me.
EDIT:
OK, my answer was incomplete. Here is a complete and working example:
class Message
class One extends Message
class Two extends Message
type Handler[A <: Message, B <: Message] = A => B
def regHandler[A <: Message, B <: Message](a: A)(handler: Handler[A, B]): Unit = {
println(s"${handler(a)}")
}
def handler(one: One) : Two = {
new Two
}
regHandler(new One)(handler)
EDIT 2:
For usage in a map function or to assign to a var/val in this specific scenario add _:
val f: Handler[_, _] = handler _
val map = Map(new One -> handler _)
val test = map.map {case (one, h) => h(one)}

You can use variance annotation with wildcard types. Check this:
object Main {
class Message
class One extends Message
class Two extends Message
class Three extends Message
class Four extends Message
type HandlerType[+A <: Message, +B <: Message] = A => B
var f: HandlerType[_, _] = _
def regHandler(handler: HandlerType[_, _]) = {
f = handler // <- but cast error here occurred
}
def main(args: Array[String]) {
def handler12(x: One): Two = new Two
def handler23(x: Two): Three = new Three
def handler34(x: Three): Four = new Four
val h12 = handler12(_)
val h23 = handler23(_)
val h34 = handler34(_)
val handlersMap: Map[String, HandlerType[_, _]] = Map(
"12" -> h12,
"23" -> h23,
"34" -> h34)
handlersMap foreach {
case (k, h) =>
println(k)
println(h)
val hd: HandlerType[Message, Message] = h
val m: Message = new One
println(hd(m))
}
regHandler(h12)
}
}
Although you can store the handlers into a map, it creates additional types which introduce more complexity. I think there should be a better way to handle this problem.

Related

Generic stream and abstract data types

Here is a strawman program which illustrates the issue I am having
trait RequestBuilder {
type Out
def complete(p: Promise[Out]): Unit
}
def makeRequest(in: RequestBuilder): Source[(RequestBuilder, Promise[in.Out]), Future[in.Out]] = {
val p = Promise[in.Out]
Source.single(in -> p).mapMaterializedValue(_ => p.future)
}
val sink = MergeHub.source[(RequestBuilder, Promise[???])].to(Sink.foreach {
case (r, p) => r.complete(p)
}).run()
sink.runWith(makeRequest(new RequestBuilder {
type Out = Int
def complete(p: Promise[Out]): Unit = p.success(1)
}))
The issue is, how do I type the Promise[???] in the sink? I have been able to work around this by making the Promise a part of the RequestBuilder trait itself, but this seems like a code smell to me
You can make a type alias for the tuple:
type BuilderWithPromise[B <: RequestBuilder] = (B, Promise[B#Out])
Or a case class:
case class BuilderWithPromise[B <: RequestBuilder)(
builder: B,
promise: Promise[B#Out]
)
either way should work

Elegant way to chain Scala partial functions

I am looking for an elegant way to chain partial functions that derive from a common base type. The idea is that each partial function handles a type so they become easy to compose for different types and have a common catch-all if the chained partial function is undefined:
trait Message
trait SysMessage extends Message
trait UserMessage extends Message
case class TextSysMessage(m: String) extends SysMessage
case class TextUserMessage(m: String) extends UserMessage
class Test {
type MessagePF = scala.PartialFunction[Message, String]
type SysMessagePF = scala.PartialFunction[SysMessage, String]
type UserMessagePF = scala.PartialFunction[UserMessage, String]
def getSysMessage: SysMessagePF = {
case sm: TextSysMessage ⇒ s"System message: ${sm.m}"
}
def getUserMessage: UserMessagePF = {
case um: TextUserMessage ⇒ s"User message: ${um.m}"
}
def * : MessagePF = {
case m ⇒ s"Unknown message: $m"
}
// Chained partials fails because `m` is a SysMessage with UserMessage
def handler(m: Message): String = (getSysMessage orElse getUserMessage orElse *)(m)
}
Clearly, this approach does not compile. I can get around this by nested pattern matching like this
def getSysMessage: MessagePF = {
case m: SysMessage ⇒ m match {
case sm: TextSysMessage ⇒ s"System message: ${sm.m}"
}
}
but then I loose the capability of handling unknown messages in a catch all. Is there some elegant way to achieve this goal?
As addition to #adamwy + Hongxu Chen's answer, you can define your very own combinator, which involves implicit parameters, so enforces slightly different application syntax
implicit class PartFuncOps[A: ClassTag, B](pf: PartialFunction[A, B]) {
def or[D >: A, C <: D : ClassTag](other: PartialFunction[C, B]): PartialFunction[D, B] = {
case a: A if pf.isDefinedAt(a) ⇒ pf(a)
case c: C if other.isDefinedAt(c) ⇒ other(c)
}
}
Now you can write
def combine = getSysMessage or getUserMessage or *
def handler(m: Message): String = combine(m)
Or
def handler(m: Message): String = (getSysMessage or getUserMessage or *).apply(m)
As suggested by #adamwy, you can change the partial function type to be:
type MessagePF = scala.PartialFunction[Message, String]
type SysMessagePF = scala.PartialFunction[Message, String]
type UserMessagePF = scala.PartialFunction[Message, String]

How to overload the product method of a typeclass

I am trying to implement a ReadJsonCodec of sorts using the automatic type class derivation mechanism in Shapeless.
Here is my ReadCodecCompanionObject:
object ReadCodec extends LabelledProductTypeClassCompanion[ReadCodec] {
implicit object StringCodec extends SimpleCodec[String] {
def read(j: Json): String = j.stringOr(throw ...)
}
implicit object IntCodec ...
implicit object BooleanCodec ...
implicit object LongCodec ...
implicit object ShortCodec ...
implicit object DoubleCodec ...
implicit object BigDecimalCodec ...
implicit def readCodecInstance: LabelledProductTypeClass[ReadCodec] = new LabelledProductTypeClass[ReadCodec] {
def emptyProduct = new ReadCodec[HNil] {
// This will silently accept extra fields within a JsonObject
// To change this behavior make sure json is a JsonObject and that it is empty
def read(json: Json) = HNil
}
def product[F, T <: HList](name: String, FHead: ReadCodec[F], FTail: ReadCodec[T]) = new ReadCodec[F :: T] {
def read(json: Json): F :: T = {
val map = castOrThrow(json)
val fieldValue = map.getOrElse(name, throw new MappingException(s"Expected field $name on JsonObject $map"))
// Try reading the value of the field
// If we get a mapping exception, intercept it and add the name of this field to the path
// If we get another exception, don't touch!
// Pitfall: if handle did not accept a PartialFunction, we could transform an unknow exception into a match exception
val head: F = Try(FHead.read(fieldValue)).handle{ case MappingException(msg, path) => throw MappingException(msg, s"$name/$path")}.get
val tail = FTail.read(json)
head :: tail
}
}
def product[A, T <: HList](name: String, FHead: ReadCodec[Option[A]], FTail: ReadCodec[T]) = new ReadCodec[Option[A] :: T] {
def read(json: Json): Option[A] :: T = {
val map = castOrThrow(json)
val head: Option[A] = map.get(name).map { fieldValue =>
Try(FHead.read(fieldValue)).handle{ case MappingException(msg, path) => throw MappingException(msg, s"$name/$path")}.get.get
}
val tail = FTail.read(json)
head :: tail
}
}
def project[F, G](instance: => ReadCodec[G], to : F => G, from : G => F) = new ReadCodec[F] {
def read(json: Json): F = from(instance.read(json))
}
}
}
That's somewhat of a complicated piece of code to just grasp quickly but is really fairly simple once you understand it. The important part is the two def product methods. The problem I am having is that I want this codec to accept a Json AST that is missing a field if that field would be mapped to a value of type Option[A]. This means that I need the product function to know if the head of the HList is of type Option[A] or not.
Concretely:
case class Foo(a: String, b: Option[Boolean])
val test = read[Foo](json"""{"a" : "Beaver"}""") // should work
But currently this would fail because it makes no distinction for Option and expects a field b. I tried two ways of fixing this and neither of them worked.
The first one and the cleanest one is to overload the product method with a version where the F type parameter is replaced with Option[A]. This approach is fairly clean, although I am not sure whether or not it would play well with the shapeless derivation macro. However, it is not possible because Scala does not support the ability to overload functions when the type signature after erasure is the same. This is the version that is above. Unfortunately, this does not currently compile with the Scala compiler.
The second approach was to use a TypeTag to find out at runtime if F is of type Option[_] and behave appropriately. This version would almost certainly be less elegant and involve a cast but I could live with it. However, it seems impossible because the addition of a TypeTag changes the signature of the product method (adding an implicit parameter) and then the compiler complains that I am not defining the abstract method product.
Does anyone have any suggestions on the best way to proceed.
You need to get a typeclass with information about F passed through. But you're already passing a typeclass around, in the form of ReadCodec. So the solution is to replace that with one that contains all the information you need:
trait ReadCodecAndTypeTag[A] {
val rc: ReadCodec[A]
val tt: TypeTag[A]
}
But in that case you might as well delegate the decoding-from-optional-value-in-a-map to this typeclass as well:
trait OReadCodec[A] {
val rc: ReadCodec[A]
def missingField(name: String, map: Any): A =
throw new MappingException(s"Expected field $name on JsonObject $map")
}
implicit object StringCodec extends OReadCodec[String] {
val rc = new ReadCodec[String] {...}
}
implicit object IntCodec ...
...
implicit def OptionCodec[A](implicit orc: OReadCodec[A]) =
new OReadCodec[Option[A]] {
val rc = ...
override def missingField(name: String, map: Any) = None
}
...
def product[F, T <: HList](name: String, FHead: OReadCodec[F], FTail: OReadCodec[T]) =
new OReadCodec[F :: T] {
val rc = new ReadCodec[F :: T] {
def read(json: Json): F :: T = {
val map = castOrThrow(json)
val fieldValue = map.getOrElse(name, FHead.missingField(name, map))
val head: F = ...
...
}
}
}
implicit def ReadCodecFromOReadCodec[A](implicit orc: OReadCodec[A]) = orc.rc

datastructure that holds closures, parametrically in 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.

How is this a type mismatch?

val eventListeners = new HashMap[Class[Event], ArrayBuffer[Event => Unit]]
def addEventListener[A <: Event](f: A => Unit)(implicit mf: ClassManifest[A]): A => Unit = {
eventListeners.getOrElseUpdate(mf.erasure.asInstanceOf[Class[Event]], ArrayBuffer[Event => Unit]()) += f
f
}
Is throwing:
error: type mismatch;
found : (A) => Unit
required: (this.Event) => Unit
eventListeners.getOrElseUpdate(mf.erasure.asInstanceOf[Class[Event]], ArrayBuffer[Event => Unit]()) += f
Why is it saying that it found (A) => Unit? The value of f is a function that is (Event) => Unit. Isn't A just a type parameter, not the signature?
Example call:
addEventListener { e:FooEvent => .... }
The class Function1 is contra-variant on its parameter. Ie, its type is Function1[-T, +R].
That means a function of Any => Unit is a subtype of Event => Unit, but for A a subtype of Event, A => Unit is a _super_type of Event => Unit.
Ergo, the problem. If you change the type parameter to A >: Event, it should work.
You are promising your ArrayBuffer that you will give it a function that can take any Event and turn it into a Unit (presumably doing something interesting along the way).
But you are giving it a function that can only take As, which may not encompass all Events. That is clearly not what you've promised, so the compiler complains.
You need to figure out what ought to happen in that case, and write code accordingly. For example, you could create a new function g that does nothing in case it receives an Event that, according to your class manifest, is not an A, and otherwise applies f. Or you could require all listeners to take events of all sorts, and be responsible themselves for throwing away the events that they don't want to bother with.
Edit: just to make things clearer with an example,
abstract class Fruit { def tasty: String }
class Banana extends Fruit { def tasty = "Yum!" }
abstract class SeededFruit extends Fruit {
def seedCount: Int
def tasty = "Mmm, mmm."
}
class Peach extends SeededFruit { def seedCount = 1 }
class Apple extends SeededFruit { def seedCount = 5 }
val tellAboutSeeds = (sf: SeededFruit) => println("There are "+sf.seedCount+"seeds")
val fruitTeller = new collection.mutable.ArrayBuffer[Fruit=>Unit]
fruitTeller += tellAboutSeeds // If this worked...
fruitTeller(0)(new Banana) // ...we'd be in trouble!