Type system not allowing subtype as a type constructor - scala

I'm trying to build the following type structure for a library I'm writing, and I'm having trouble with the type system.
CarLike
trait CarLike[T, C <: CarLike[T,C]] {
val parts: Seq[T]
def crash(other: C, speed: Int): C
//... other methods
}
SimpleCar
class SimpleCar[T](val parts: Seq[T]) extends CarLike[T, SimpleCar[T]] {
def crash(other: SimpleCar[T], speed: Int) = {
//Some logic to crash with the other car
val newParts = damage(parts) //parts have changed
new SimpleCar(newParts)
}
//...other methods
}
SportsCar
class SportsCar(val sParts: Seq[String]) extends SimpleCar[String](sParts){
override def crash(other: SimpleCar[String], speed: Int): SimpleCar[String] = {
//Some other logic for crashing a sport car
val newParts = damage(parts) //parts have changed
new SportsCar(newParts)
}
//...other methods
}
Crasher
case class Crasher[T, C <: CarLike[T,C]](
partsDamager: T => T,
carChecker: C => Seq[T]
/*... more parameters*/
){
def test(cycles:Int) = {
//Some logic to run a crash of two cars
}
}
Code
//...
val crasher = Crasher[String, SportsCar](
(s: String) => s.tail,
(c: SportsCar) => c.parts.filter(p => p.length > 0)
/*Many arguments*/
)
crasher.test(20)
//...
The idea is to allow the user of the library to be able to choose between using the default SimpleCar and implementing his own implementation of CarLike.
Also, users can choose the type for the car's parts. In this simple example the parts are String, but can easily be a custom class, which can be leveraged in the crash method of a custom class.
When compiling, I get the following compilation error:
type arguments [String,my.package.SportsCar] do not conform to method apply's type parameter bounds [T,C <: crashing.CarLike[T,C]]
val crasher = Crasher[String, SportsCar](
Clearly there's something I'm missing here. Why doesn't the compiler agree that SportsCar is a legal subtype of CarLike?

A SportsCar is not a CarLike[String, SportsCar], it is a CarLike[String, SimpleCar[String]]. Note that SportsCar extends SimpleCar[String], but that doesn't help, as CarLike is not covariant in C.
You can't really make CarLike covariant in C, as its crash method accepts a C. Instead, you can pass SimpleCar[String] to Crasher (after all, sports cars can crash with other cars, right?):
val crasher = Crasher[String, SimpleCar[String]](
s => s.tail,
c => c.parts.filter(p => p.length > 0)
)
Or, you can modify Crasher to take another type parameter:
case class Crasher[T, C <: CarLike[T, C], X <: C](partsDamager: T => T,
carChecker: X => Seq[T]) {
// ...
}
val crasher = Crasher[String, SimpleCar[String], SportsCar](
s => s.tail,
c => c.parts.filter(p => p.length > 0)
)

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)

Implicit class on Iterable of my type and its subtypes

I'm trying to learn good practices to create a DSL using the rich possibilities of Scala but I've faced the following problem : I'm unable to create an implicit class that applies to all subtypes of Iterable (arrays, lists,...) and that matches only subtypes of a specific type I defined (in the example: Fruit).
Here's what I've came up with so far (it's a simplified version of my code) :
sealed trait Fruit { // My main type
type A <: Fruit
def setSize(v: Int): Unit = this match {
case multi: MultiFruit[_] => multi.foreach(_.setSize(v))
case or: Orange => or.size = v
case ap: Apple => ap.size = v
case _ => throw new Exception
}
}
case class MultiFruit[F <: Fruit](var l: List[F]) extends Fruit {
type A = F
def foreach[B](f: F => B) : Unit = l.foreach(f)
}
case class Orange(var size: Int) extends Fruit {
type A = Orange
}
case class Apple(var size: Int) extends Fruit {
type A = Apple
}
object Fruit {
implicit class IterableFruit[F <: Fruit, I <: Iterable[F]](val ite: I) extends AnyVal {
def setSize(v: Int): Unit = ite.foreach(_.setSize(v)) // Apply setSize on every Fruit of the iterable
def ++[F2 <: Fruit, I2 <: Iterable[F2]](ite2: I2): MultiFruit[_ <: Fruit] = new MultiFruit[Fruit](ite.toList++ite2.toList)
}
}
So here is my problem: when I try to run this
object Main {
import Fruit._
def main(args: Array[String]): Unit = {
val oranges = Array.tabulate(5)(i => Orange(i*10))
val apples = Array.tabulate(5)(i => Apple(i*10))
oranges setSize 20 // setSize is not found, it doesn't match Iterable[Fruit]
val or_ap = oranges ++ apples // ++ not found (the compiler wants to use the one defined in Array)
}
}
My method setSize and ++ are not found.
What makes me even more confused is that my IDE (IntelliJ) founds the setSize method (and doesn't report any error) but the IDE thinks that the ++ is the one defined in Array and not in my implicit class.
I think my problem comes from the way I typed my IterableFruit class, but ressources I found on extension methods is very limited (and never really go in depth) and I can't figure out what's wrong.
Edit:
Also, when I modified my implicit class to:
object Fruit {
implicit class IterableFruit[F <: Fruit](val ite: Array[F]) extends AnyVal {
def setSize(v: Int): Unit = ite.foreach(_.setSize(v)) // Apply setSize on every Fruit of the iterable
def ++[F2 <: Fruit](ite2: Array[F2]): MultiFruit[_ <: Fruit] = new MultiFruit[Fruit](ite.toList++ite2.toList)
}
}
Everything compiles, but now it obviously doesn't work if I try to use any other iterable but an array, so I think the issue indeed come from the way I use typing in the implicit class
This can be fixed by turning your Arrays into Iterables with toIterable (The Array does not extend Iterable, since it represents a built-in Java array):
val oranges = Array.tabulate(5)(i => Orange(i*10)).toIterable
And for your ++ method to work, you have to rename it to something else, like +:+. Currently, the compiler sees no reason to do the implicit conversion, since there's already a concat/++ method on your oranges object.
Link to Scastie

How to return correct type from generic function passed a related abstract type parameter

I am trying to write "better" (more idiomatic?) Scala code for the following circumstance:
I have a set of classes that will be identified by a reference field that belongs to a parallel set of reference case classes, something like the following:
abstract sealed class Ref(value: String)
case class ARef(value: String) extends Ref(value)
case class BRef(value: String) extends Ref(value)
case class CRef(value: String) extends Ref(value)
trait Referenced {
type refType <: Ref
val ref: refType
}
trait A extends Referenced { type refType = ARef }
trait B extends Referenced { type refType = BRef }
trait C extends Referenced { type refType = CRef }
Another class (which will probably turn into the state type of a State monad) will contain lists of these types, and provide a function to retrieve an object, given its reference. I want this returned value to be appropriately typed, i.e. given
val aRef = ARef("my A ref")
I want to be able to make a call like:
val myA: Option[A] = context.get[A](aRef)
and be sure to get back an Option[A], not just an Option[Referenced]. My best attempt to achieve this so far looks something like the following:
trait Context {
// ... other stuff ...
protected val aList: List[A]
protected val bList: List[B]
protected val cList: List[C]
def get[R <: Referenced](ref: R#refType): Option[R] = {
val result = ref match {
case aRef: ARef => aList.find(_.ref == aRef)
case bRef: BRef => bList.find(_.ref == bRef)
case cRef: CRef => cList.find(_.ref == cRef)
case _ => throw new RuntimeException("Unknown Ref type for retrieval: "+ref)
}
result.asInstanceOf[Option[R]]
}
}
which seems to work correctly, but has that smelly "asInstanceOf" call in it. I would be interested in seeing ideas on how this might be done better (and check that I haven't just missed an obvious simpler solution).
Note that for other reasons, I have thus far elected to go with abstract typing rather than parameter types (trait A extends Referenced[ARef] style), but could change this if the reasons were compelling enough.
The machinery needed to do this without casting really isn't all that heavy in this case ... it's just another example of a functional dependency.
In what follows we rely on the fact that type Ref is sealed so that we can simply enumerate the alternatives. Your Ref and Reference hierarchies remain unchanged, and we add a relation type Rel to both express the type-level correspondence between the two, and to make an appropriate value-level selection,
trait Rel[Ref, T] {
def lookup(as: List[A], bs: List[B], cs: List[C])(ref: Ref) : Option[T]
}
object Rel {
implicit val relA = new Rel[ARef, A] {
def lookup(as: List[A], bs: List[B], cs: List[C])(ref: ARef) : Option[A] =
as.find(_.ref == ref)
}
implicit val relB = new Rel[BRef, B] {
def lookup(as: List[A], bs: List[B], cs: List[C])(ref: BRef) : Option[B] =
bs.find(_.ref == ref)
}
implicit val relC = new Rel[CRef, C] {
def lookup(as: List[A], bs: List[B], cs: List[C])(ref: CRef) : Option[C] =
cs.find(_.ref == ref)
}
}
Now we can reimplement Context without pattern matches or casts as follows,
trait Context {
// ... other stuff ...
protected val aList: List[A] = ???
protected val bList: List[B] = ???
protected val cList: List[C] = ???
def get[R <: Ref, T](ref: R)(implicit rel: Rel[R, T]): Option[T] =
rel.lookup(aList, bList, cList)(ref)
}
And we can use this new definition like so,
object Test {
def typed[T](t: => T) {} // For pedagogic purposes only
val context = new Context {}
val aRef = ARef("my A ref")
val myA = context.get(aRef)
typed[Option[A]](myA) // Optional: verify inferred type of myA
val bRef = BRef("my B ref")
val myB = context.get(bRef)
typed[Option[B]](myB) // Optional: verify inferred type of myB
val cRef = CRef("my C ref")
val myC = context.get(cRef)
typed[Option[C]](myC) // Optional: verify inferred type of myC
}
Notice that the resolution of the implicit Rel argument to get computes the type of the corresponding Reference from the type of the ref argument, so we're able to avoid having to use any explicit type arguments at get's call-sites.
I am just going to reiterate my own (current) "answer" for my question, because I thought it would be interesting/instructive to allow readers to vote it up or down to generate a more direct comparison with answers provided by others.
trait Context {
// ... other stuff ...
protected val aList: List[A]
protected val bList: List[B]
protected val cList: List[C]
def get[R <: Referenced](ref: R#refType): Option[R] = {
val result = ref match {
case aRef: ARef => aList.find(_.ref == aRef)
case bRef: BRef => bList.find(_.ref == bRef)
case cRef: CRef => cList.find(_.ref == cRef)
case _ => throw new RuntimeException("Unknown Ref type for retrieval: "+ref)
}
result.asInstanceOf[Option[R]]
}
}

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!