types as mold to delegated classes in Scala - scala

I am working in ScalaFX Project. In this moment I am adapting classes from javafx.scene.control.cell. In this package, methods with same signature are duplicated in many classes. e.g. StringConverter<T> converter(). To avoid unnecessary duplication of code (and to know how to use existential types), I created the following code:
// Defined in scalafx.util package. All classes in scalafx use this trait
package scalafx.util
trait SFXDelegate[+D <: Object] extends AnyRef {
def delegate: D
override def toString = "[SFX]" + delegate.toString
override def equals(ref: Any): Boolean = {
ref match {
case sfxd: SFXDelegate[_] => delegate.equals(sfxd.delegate)
case _ => delegate.equals(ref)
}
}
override def hashCode = delegate.hashCode
}
// Package Object
package scalafx.scene.control
import javafx.{ util => jfxu }
import javafx.beans.{ property => jfxbp }
import javafx.scene.{ control => jfxsc }
import scalafx.Includes._
import scalafx.beans.property.ObjectProperty
import scalafx.util.SFXDelegate
import scalafx.util.StringConverter
package object cell {
type Convertable[T] = {
def converterProperty: jfxbp.ObjectProperty[jfxu.StringConverter[T]]
}
type JfxConvertableCell[T] = jfxsc.Cell[T] with Convertable[T]
trait ConvertableCell[C <: JfxConvertableCell[T], T]
extends SFXDelegate[C] {
def converter: ObjectProperty[StringConverter[T]] = ObjectProperty(delegate.converterProperty.getValue)
def converter_=(v: StringConverter[T]) {
converter() = v
}
}
}
In JfxConvertableCell type I wanna say
My type is a javafx.scene.control.Cell of type T that has a method called converterProperty that returns a javafx.beans.property.ObjectProperty of type javafx.util.StringConverter[T].
While in ConvertableCell trait, my intention is say that delegate value (from SFXDelegate trait) must be of type JfxConvertableCell. The first class that I tried to create was the counter-part of CheckBoxListCell:
package scalafx.scene.control.cell
import javafx.scene.control.{cell => jfxscc}
import scalafx.scene.control.ListCell
import scalafx.util.SFXDelegate
class CheckBoxListCell[T](override val delegate: jfxscc.CheckBoxListCell[T] = new jfxscc.CheckBoxListCell[T])
extends ListCell[T](delegate)
with ConvertableCell[jfxscc.CheckBoxListCell[T], T]
with SFXDelegate[jfxscc.CheckBoxListCell[T]] {
}
However in this moment I got this message from compiler:
type arguments [javafx.scene.control.cell.CheckBoxListCell[T],T] do not conform to trait ConvertableCell's type parameter bounds [C <: scalafx.scene.control.cell.package.JfxConvertableCell[T],T]
Did I understand something wrong? CheckBoxListCell have the converterProperty method. Can't we use types and existential types as a mold into which we fit our delegated classes?

The problem is in your definition of converterProperty. You define it as a parameterless method, while it is seen by scala as a method with an empty parameter list.
Just doing this makes it compile properly:
type Convertable[T] = {
def converterProperty(): jfxbp.ObjectProperty[jfxu.StringConverter[T]]
}
While scala treats a parameterless method and a method with an empty parameter list as essentially the same thing as far as overriding is concerned (see scala spec # 5.1.4), they are still different entites.
And when interroperating with java code (which has no notion of parameterless method), a nullary method is seen as a method with an empty prameter list, not as a parameterless method, thus the structural types don't match.

Related

TypeTag for case classes

I would like to make a case class Bla that takes a type parameter A and it knows the type of A at runtime (it stores it in its info field).
My attempt is shown in the example below. The problem is that this example does not compile.
case class Bla[A] (){
val info=Run.paramInfo(this) // this does not compile
}
import scala.reflect.runtime.universe._
object Run extends App{
val x=Bla[Int]
def paramInfo[T](x:T)(implicit tag: TypeTag[T]): String = {
val targs = tag.tpe match { case TypeRef(_, _, args) => args }
val tinfo=s"type of $x has type arguments $targs"
println(tinfo)
tinfo
}
paramInfo(x)
}
However when I comment val info=Run.paramInfo(this) then the program runs fine and prints:
type of Bla() has type arguments List(Int)
Is there a way to make this example below compile ? (or in some other way achieve the same goal, i.e. that a case class is self aware of the type of it's type parameter?)
There's little point in using reflection based APIs for this, shapeless has a typeclass that exposes compile time information to runtime using an implicit macro.
import shapeless.Typeable
class Test[T : Typeable] {
def info: String = implicitly[Typeable[T]].describe
}
It's also relatively easy to roll your own thing here, with the added inconvenience of having to compile the implicit macro in a different compilation unit than whatever is using it.
You just need to pass the implicit type tag parameter to the case class constructor (otherwise the type information is lost before calling paraInfo which requires it):
case class Bla[A : TypeTag]() { ... }
Which is shorthand for:
case class Bla[A](implicit tag: TypeTag[A]) { ... }

Compile time structural typing of close method

I've got the following helper method in my project:
def close(c: Closeable) {
Option(c).foreach(s => Try(s.close))
}
I've got some classes that have a close method but do not implement Closeable. If I change the helper method to use structural types I can still use it on these classes:
def close(c: {def close()}) {
Option(c).foreach(s => Try(s.close))
}
However this introduces use of reflection which is something that I'd like to avoid in runtime.
Is there a way to use something similar to structural typing without inducing runtime reflection?
I.e in the same way Shapeless allows generic access to fields, maybe implicit parameters + macros could be used to access methods in the same way?
Use traits to implement the typeclass pattern.
When I wrote my original solution it was a bit rough round the edges as I assumed a quick search for convert structural bounds to context bounds would pull up better explanations than I could write. That doesn't seem to be the case. Below is a compiling solution.
object Closeables {
trait MyCloseable[A] {
def myClose(a: A): Unit
}
object MyCloseable {
implicit object MyCanBeClosed extends MyCloseable[CanBeClosed] {
def myClose(c: CanBeClosed) = c.nonStandardClose()
}
}
}
class CanBeClosed {
def nonStandardClose(): Unit = println("Closing")
}
import Closeables._
object Test extends App {
def functionThatCloses[A: MyCloseable](a: A) {
implicitly[MyCloseable[A]].myClose(a)
}
def functionThatClosesExplicit[A](a: A)(implicit ev: MyCloseable[A]) {
ev.myClose(a)
}
val c = new CanBeClosed
functionThatCloses(c)
functionThatClosesExplicit(c)
functionThatCloses(c)(MyCloseable.MyCanBeClosed)
functionThatClosesExplicit(c)(MyCloseable.MyCanBeClosed)
}
For each type of class that can be accepted by functionThatCloses you must define and implicit object in MyCloseables.
The compiler looks at the context bound in functionThatCloses and converts it to a function with the definition of functionThatClosesExplicitly.
The compiler than 'finds' the implicit 'evidence' in the definition from the MyCloseables object and uses that.

Using abstract types with type classes in Scala

I want to use an abstract type Value constrained to belong to the type class Show from cats.
My first attempt would be something like:
package examples
import cats._
import cats.data._
import cats.implicits._
class UsingShow1 {
type Value <: Show[Value] // Not sure if this declaration is right
def showValues(vs: List[Value]): String =
vs.map(implicitly[Show[Value]].show(_)).mkString // Error line
}
But the compiler doesn't find the implicit parameter Show[Value].
I know that I can define the previous example as:
class UsingShow2[Value: Show] {
def showValues(vs: List[Value]): String =
vs.map(implicitly[Show[Value]].show(_)).mkString
}
However, I wanted to know if it is possible to use abstract types instead of type parameters.
Simply add an implicit parameter of type Show[Value], at use site, as usual:
class UsingShow1 {
type Value
def showValues(values: List[Value])(implicit showValue: Show[Value]): String =
values.map(showValue.show).mkString
}
But a more direct translation of your UsingShow2 class would be the following:
class UsingShow1 {
type Value
implicit def showValue: Show[Value]
def showValues(values: List[Value]): String =
values.map(showValue.show).mkString
}
Basically, since you’ve traded your type parameter Value for an abstract type member, you also have to trade your implicit parameter for an implicit abstract member (showValue in my example).

Extend generic type - PriorityQueue

I can't understand why I need () and hence where MyTypeQueOrdering goes.
Here is header of PriorityQueue, found on official github:
class PriorityQueue[A](implicit val ord: Ordering[A])
Here is my try (which works):
class MyType{
}
object MyTypeQueOrdering extends Ordering[MyType]{
def compare (n1:MyType, n2:MyType) = -1
}
class MyTypeQue extends PriorityQueue[MyType]()(MyTypeQueOrdering){
}
... but I can't figure out why I need (). Does PriorityQueue[MyType]() return something?
Try making MyTypeQueOrdering an implicit object:
object Implicits {
//implicit objects can't be top-level ones
implicit object MyTypeQueOrdering extends Ordering[MyType] {
def compare(n1: MyType, n2: MyType) = -1
}
}
This way you can omit both parentheses:
import Implicits._
class MyTypeQue extends PriorityQueue[MyType] { ... }
The reason you need the empty parentheses in your example is because PriorityQueue[MyType](MyTypeQueOrdering) would assume you're trying to pass the ordering as a constructor parameter. So that's why you need to explicitly show no-arg instantiation and then passing the ordering

getting "incompatibe type" in returning an object instace

I'm writing a Play! 2.1 application using ReactiveMongo. each persistable case class has an object that holds 2 implicit objects, implementing BSONReader[...] and BSONWriter[...], and each case class has methods to return these:
trait Persistable {
implicit def getReader: BSONReader[Persistable]
implicit def getWriter: BSONWriter[Persistable]
val collectionName: String
}
case class MyObj () extends Persistable {
override val collectionName: String = MyObj.collectionName
override def getReader: BSONReader[MyObj] = MyObj.MyObjBSONReader
override def getWriter: BSONWriter[MyObj] = MyObj.MyObjBSONWriter
}
object MyObj{
val collectionName: String = "MyObj"
implicit object MyObjBSONReader extends BSONReader[MyObj] {
def fromBSON(document: BSONDocument): MyObj = {
val doc = document.toTraversable
new MyObj(
)
}
}
implicit object MyObjBSONWriter extends BSONWriter[MyObj] {
def toBSON(myObj: MyObj) = {
BSONDocument(
)
}
}
for some reason, getReader seems to work fine, but getWriter errors:
overriding method getWriter in trait Persistable of type =
reactivemongo.bson.handlers.BSONWriter[models.persistable.Persistable];
method getWriter has incompatible type
what am i doing wrong? both seem to have similar signatures.
another hint is that if i remove the return type from getWriter, i get complie time error in eclipse:
type mismatch; found : models.persistable.MyObj.MyObjBSONWriter.type required:
reactivemongo.bson.handlers.BSONWriter[models.persistable.Persistable]
UPDATE:
I did as #AndrzejDoyle said below, but then the implementation of Persister, which was the heart of this exercise, complains:
def insert(persistable: Persistable) = {
val collection = db(persistable.collectionName)
import play.api.libs.concurrent.Execution.Implicits._
implicit val reader = persistable.getReader
implicit val writer = persistable.getWriter
collection.insert(persistable)
}
error:
trait Persistable takes type
parameters
It is due to covariance and contravariance.
The mongodb reader is defined as BSONReader[+DocumentType]. The + in the generic parameter, means that this class is covariant in that parameter. Or more fully,
If B is a subclass of A, then BSONReader[B] is a subclass of BSONReader[A].
Therefore you can use a BSONReader[MyObj] everywhere that a BSONReader[Persistable] is required.
On the other hand, the writer is contravariant: BSONWriter[-DocumentType]. This means that
If B is a subclass of A, then BSONWriter[B] is a superclass of BSONWriter[A].
Therefore your BSONWriter[MyObj] is not a subclass of BSONWriter[Persistable], and so cannot be used in its place.
This might seem confusing initially (i.e. "why does contravariance make sense when it's 'backwards'?"). However if you think about what the classes are doing, it becomes clearer. The reader probably produces some instance of its generic parameter. A caller then might expect it to produce a Persistable - if you have a version that specifically produces MyObjs instead then this is fine.
The writer on the other hand, is probably given an object of its generic parameter. A caller with a BSONWriter[Persistable] will call the write() method, passing in an instance of Persistable to be written. Your implementation can only write instances of MyObj, and so it doesn't actually match the interface. On the other hand, a BSONWriter[Object] would be a subclass of any BSONWriter, since it can (from a type perspective) accept any type as an argument.
The fundamental problem seems to be that your Persistable trait is looser than you intended. You probably want each implementation to return a reader and writer parameterized on itself, rather than on Persistable in general. You can achieve this via self-bounded generics:
trait Persistable[T <: Persistable[T]] {
implicit def getReader: BSONReader[T]
implicit def getWriter: BSONWriter[T]
val collectionName: String
}
and then declare the class as MyObj[MyObj]. Now the reader and writer are expected to be parameterised on MyObj, and your existing implementations will compile.