Subclassing classes that have type parameters - scala

Trying some basic graphing stuff in scala and ran into something which I think SO community can help with.
First. I have a graph trait defined
trait GraphLike[T] { ... }
and a sub-class
class DiGraph[T] extends GraphLike[T] { ... }
I also have a BreadthFirstSearch Class which looks like this:
class BreadthFirstSearch[ T ]( val graph: GraphLike[T], val sourceVertex: T ) extends Graphsearch.GraphSearch[ T ]{
I'm trying to use this in another class which looks like this:
class SAP[T]( val graph: DiGraph[T]) {
class inSap[T]( val v: T, val w: T )
{
val bfsV = new BreadthFirstSearch[T](graph, v)
}
}
I'm running into a compiler error when calling new BreadthFirstSearch.
BreadthFirstSearch takes a GraphLike parameter. The SAP class has a graph: DiGraph[T] and DiGraph is a subclass of GraphLike, so I would expect to be able to call the constructor of BreadthFirstSearch using a graph parameter of type DiGraph because DiGraph is GraphLike.
However, the compiler says this:
type mismatch; found : com.KGraph.DiGraph[T(in class SAP)] required: com.KGraph.GraphLike[T(in class
inSap)]
Its doesn't like me using the sub-class DiGraph in place of a GraphLike. Any idea why this would happen? I'm guessing this may have to do with the Type Parameters. All the classes are invariant on the type parameter.
I didn't think anything other than the class constructor definitions were needed to help with this, however, if more code is needed to figure stuff out, please update and I will provide the code.

When you defined your inner class:
class inSap[T]( val v: T, val w: T )
You introduced a second type variable named T. So when you call new BreadthFirstSearch[T] that is using the T from inSap, not the T from SAP. You should just need to remove the type parameter from inSap, so that inside that class, T just refers the the type in the outer scope.

Related

Scala: Multiple type parameters for implicit class

I'm trying to port parts of a Haskell library for datatype-generic programming to Scala. Here's the problem I've run into:
I've defined a trait, Generic, with some container-type parameter:
trait Generic[G[_]] {
// Some function declarations go here
}
Now I have an abstract class, Collect, with three type parameters, and a function declaration (it signifies a type than can collect all subvalues of type B into a container of type F[_] from some structure of type A):
abstract class Collect[F[_],B,A] {
def collect_ : A => F[B]
}
In order to make it extend Generic, the first two type parameters F[_] and B are given, and A is curried (this effect is simulated using type lambdas):
class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] {
// Function definitions go here
}
The problem is that I need the last class definition to be implicit, because later on in my code I will need to be able to write functions like
class GUnit[G[_]](implicit gg: Generic[G]) {
// Some definitions
}
When I simply prepend implicit to the class definition, I get the an error saying implicit classes must accept exactly one primary constructor parameter. Has anyone encountered a similar problem? Is there a known way to work around it? I don't currently see how I could refactor my code while keeping the same functionality, so any advice is welcome. Thanks in advance!
Implicit classes don't work that way. They are a shorthand for implicit conversions. For instance implicit class Foo(i: Int) is equal to class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i). So it only works with classes that have exactly one parameter in their constructor. It would not make sense for most 0 parameter (type-)classes.
The title of your question also seems to suggest that you think the compilation error is talking about type parameters of the type constructor, but I hope the above paragraph also makes clear that it is actually talking about value parameters of the value constructor.
For what (I think) you are trying to do, you will have to provide an implicit instance of CollectC yourself. I suggest putting it in the companion object of Collect. But you can choose an alternative solution if that fits your needs better.
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Generic[G[_]] {
// Some function declarations go here
}
abstract class Collect[F[_],B,A] {
def collect_ : A => F[B]
}
object Collect {
implicit def mkCollectC[F[_],B]: CollectC[F,B] = new CollectC[F,B]
}
class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] {
// Function definitions go here
}
// Exiting paste mode, now interpreting.
warning: there were four feature warnings; for details, enable `:setting -feature' or `:replay -feature'
defined trait Generic
defined class Collect
defined object Collect
defined class CollectC
scala> implicitly[Generic[({type C[X] = Collect[List,Int,X]})#C]]
res0: Generic[[X]Collect[[+A]List[A],Int,X]] = CollectC#12e8fb82

Create a companion object that mixes in a trait that defines a method which returns an object of the object's companion class

Abstract problem: Create a trait that can be mixed into the companion object of a class, to give that object a method that returns an object of that class.
Concrete problem: I'm trying to create a bunch of classes for use with RESTful service calls, that know how to serialize and de-serialize themselves, like so:
case class Foo
(
var bar : String,
var blip : String
)
extends SerializeToJson
object Foo extends DeserializeFromJson
The intended usage is like so:
var f = Foo( "abc","123" )
var json = f.json
var newF = Foo.fromJson( json )
I'm using Genson to do the serialization/deserialization, which I access through a global object:
object JSON {
val parser = new ScalaGenson( new GensonBuilder() <...> )
}
Then I define the traits like so:
trait SerializeToJson {
def json : String = JSON.parser.toJson(this)
}
trait DeserializeFromJson[T <: DeserializeFromJson[T]] {
def fromJson( json : String ) : T = JSON.parser.fromJson( json )
}
This compiles. But this does not:
object Foo extends DeserializeFromJson[Foo]
I get the following error message:
type arguments [Foo] do not conform to trait DeserializeFromJson's
type parameter bounds [T <: DeserializeFromJson[T]]
I've tried creating a single trait, like so:
trait JsonSerialization[T <: JsonSerialization[T]] {
def json(implicit m: Manifest[JsonSerialization[T]]) : String =
JSON.parser.toJson(this)(m)
def fromJson( json : String ) : T =
JSON.parser.fromJson(json)
}
Now, if I just declare case class Foo (...) extends JsonSerialization[Foo] then I can't call Foo.fromJson because only an instance of class Foo has that method, not the companion object.
If I declare object Foo extend JsonSerialization[Foo] then I can compile and Foo has a .fromJson method. But at run time, the call to fromJson thinks that T is a JsonSerialization, and not a Foo, or so the following run-time error suggests:
java.lang.ClassCastException: scala.collection.immutable.HashMap$HashTrieMap cannot be cast to ...JsonSerialization
at ...JsonSerialization$class.fromJson(DataModel.scala:14)
at ...Foo.fromJson(Foo.scala:6)
And I can't declare object Foo extends Foo because I get
module extending its companion class cannot use default constructor arguments
So I can try adding constructor parameters, and that compiles and runs, but again the run-time type when it tries to deserialize is wrong, giving me the above error.
The only thing I've been able to do that works is to define fromJson in every companion object. But there MUST be a way to define it in a trait, and just mix in that trait. Right?
The solution is to simplify the type parameter for the trait.
trait DeserializeFromJson[T] {
def fromJson( json : String )(implicit m : Manifest[T]) : T =
JSON.parser.fromJson[T](json)(m)
}
Now, the companion object can extend DeserializeFromJson[Foo] and when I call Foo.fromJson( json ) it is able to tell Genson the correct type information so that an object of the appropriate type is created.
The problem is related to how implicits work.
Genson expects a Manifest that it will use to know to what type it must deserialize. This manifest is defined as implicit in Genson, meaning that it will try to get it from implicitly available manifests in the "caller code". However in your original version there is no Manifest[T] in DeserializeFromJson.
An alternate way would be to define the DeserializeFromJson like that (which will just produce a constructor with an implicit Manifest[T] argument):
abstract class DeserializeFromJson[T: Manifest] {
def fromJson( json : String ) : T = JSON.parser.fromJson[T](json)
}
object Foo extends DeserializeFromJson[Foo]
More generally if you don't bring more value by encapsulating a lib (in this case Genson), I think you shouldn't do that. As you basically reduce the features of Genson (now people can only work with strings) and introduce problems like the one you hit.
I think your type parameter constraint were originally wrong;
you had
trait DeserializeFromJson[T <: DeserializeFromJson[T]]
With your own answer, you fully relaxed it; you needed
trait DeserializeFromJson[T <: SerializeToJson]
...which the error was trying to tell you.
The need for the implicit Manifest (ClassTag now I believe) or context-bounds was on the money.
Would be nice for Scala to allow the specification of inheritance and type-parameter constraints based on class/trait and companion object relationship, given it is already aware, to some degree, when it comes to access-modifiers and implicit scopes.

Passing a type parameter for instantiation

Why wouldn't the scala compiler dig this:
class Clazz
class Foo[C <: Clazz] {
val foo = new C
}
class type required but C found
[error] val a = new C
[error] ^
Related question - How to get rid of : class type required but T found
This is a classic generic problem that also happens in Java - you cannot create an instance of a generic type variable. What you can do in Scala to fix this, however, is to introduce a type evidence to your type parameter that captures the runtime type:
class Foo[C <: Clazz](implicit ct: ClassTag[C]) {
val foo = ct.runtimeClass.newInstance
}
Note that this only works if the class has a constructor without any arguments. Since the parameter is implicit, you don't need to pass it when calling the Foo constructor:
Foo[Clazz]()
I came up with this scheme, couldn't simplify it through a companion object thought.
class Clazz
class ClazzFactory {
def apply = new Clazz
}
class Foo(factory: ClazzFactory) {
val foo: Clazz = factory.apply
}
It's very annoying that ClazzFactory can't be an object rather than a class though. A simplified version:
class Clazz {
def apply() = new Clazz
}
class Foo(factory: Clazz) {
val foo: Clazz = factory.apply
}
This requires the caller to use the new keyword in order to provide the factory argument, which is already a minor enough annoyance relative to the initial problem. But, scala could have made this scenario all more elegant; I had to fallback here to passing a parameter of the type I wish to instantiate, plus the new keyword. Maybe there's a better way.
(motivation was to instantiate that type many times within the real Foo, that's why this is at all a solution; otherwise my pattern above is just redundantly meaningless).

Scala type mismatch: required _$1 where type _$1 <:

I'm a newbie to Scala and I'm facing an issue I can't understand and solve. I have written a generic trait which is this one:
trait DistanceMeasure[P<:DbScanPoint] {
def distance(p1:P, p2:P):Double
}
where DbScanPoint is simply:
trait DbScanPoint extends Serializable {}
Then I have the following two classes extending them:
class Point2d (id:Int, x:Double, y:Double) extends DbScanPoint {
def getId() = id
def getX() = x
def getY() = y
}
class EuclideanDistance extends DistanceMeasure[Point2d] with Serializable {
override def distance(p1:Point2d,p2:Point2d) = {
(p1.getX()-p2.getX())*(p1.getX()-p2.getX()) + (p1.getY()-p2.getY()) * (p1.getY()-p2.getY())
}
}
And at the end I have this class:
class DBScanSettings {
var distanceMeasure:DistanceMeasure[_<:DbScanPoint] = new EuclideanDistance
//...
}
My problem is that if that when I write in my test main this:
val dbScanSettings = new DBScanSettings()
dbScanSettings.distanceMeasure.distance(new Point2d(1,1,1), new Point2d(2,2,2))
I get the following compiling error:
type mismatch;
[error] found : it.polito.dbdmg.ontic.point.Point2d
[error] required: _$1 where type _$1 <: it.polito.dbdmg.ontic.point.DbScanPoint
I can't understand which is the problem. I have done a very similar thing with other classes and I got no error, so the reason of this error is quite obscure to me.
May somebody help me?
Thanks.
UPDATE
I managed to do what I needed by changing the code to:
trait DistanceMeasure {
def distance(p1:DbScanPoint, p2:DbScanPoint):Double
}
And obviously making all the related changes.
The heart of your problem is that you are defining your distanceMeasure var with an existential type, so to the compiler that type is not completely known. Then, you are calling distance which is to take two instances of type P <: DbScanPoint passing in two Point2d instances. Now, these are the correct types for the concrete class behind distanceMeasure (a new EuclideanDistance), but the way you defined distanceMeasure (with an existential), the compiler cannot enforce that Point2d instances are the right type that the concrete underlying DistanceMeasure takes.
Say for arguments sake that instead of a new EuclideanDistance, you instead instantiated a completely different impl of DistanceMeasure that did not take Point2d instances and then tried to call distance he way you have it here. If the compiler can't enforce that the underlying class accepts the arguments supplied, it's going to complain like this.
There are a bunch of ways to fix this, and the solution ultimately depends on the flexibility you need in your class structure. One possible way is like so:
trait DBScanSettings[P <: DbScanPoint] {
val distanceMeasure:DistanceMeasure[P]
//...
}
class Point2dScanSettings extends DBScanSettings[Point2d]{
val distanceMeasure = new EuclideanDistance
}
And then to test:
val dbScanSettings = new Point2dScanSettings()
dbScanSettings.distanceMeasure.distance(new Point2d(1,1,1), new Point2d(2,2,2))
But without me really understanding you requirements for what levels of abstraction you need, it's going to be up to you to define the restructure.

Implementing '.clone' in Scala

I'm trying to figure out how to .clone my own objects, in Scala.
This is for a simulation so mutable state is a must, and from that arises the whole need for cloning. I'll clone a whole state structure before moving the simulation time ahead.
This is my current try:
abstract trait Cloneable[A] {
// Seems we cannot declare the prototype of a copy constructor
//protected def this(o: A) // to be defined by the class itself
def myClone= new A(this)
}
class S(var x: String) extends Cloneable[S] {
def this(o:S)= this(o.x) // for 'Cloneable'
def toString= x
}
object TestX {
val s1= new S("say, aaa")
println( s1.myClone )
}
a. Why does the above not compile. Gives:
error: class type required but A found
def myClone= new A(this)
^
b. Is there a way to declare the copy constructor (def this(o:A)) in the trait, so that classes using the trait would be shown to need to provide one.
c. Is there any benefit from saying abstract trait?
Finally, is there a way better, standard solution for all this?
I've looked into Java cloning. Does not seem to be for this. Also Scala copy is not - it's only for case classes and they shouldn't have mutable state.
Thanks for help and any opinions.
Traits can't define constructors (and I don't think abstract has any effect on a trait).
Is there any reason it needs to use a copy constructor rather than just implementing a clone method? It might be possible to get out of having to declare the [A] type on the class, but I've at least declared a self type so the compiler will make sure that the type matches the class.
trait DeepCloneable[A] { self: A =>
def deepClone: A
}
class Egg(size: Int) extends DeepCloneable[Egg] {
def deepClone = new Egg(size)
}
object Main extends App {
val e = new Egg(3)
println(e)
println(e.deepClone)
}
http://ideone.com/CS9HTW
It would suggest a typeclass based approach. With this it is possible to also let existing classes be cloneable:
class Foo(var x: Int)
trait Copyable[A] {
def copy(a: A): A
}
implicit object FooCloneable extends Copyable[Foo] {
def copy(foo: Foo) = new Foo(foo.x)
}
implicit def any2Copyable[A: Copyable](a: A) = new {
def copy = implicitly[Copyable[A]].copy(a)
}
scala> val x = new Foo(2)
x: Foo = Foo#8d86328
scala> val y = x.copy
y: Foo = Foo#245e7588
scala> x eq y
res2: Boolean = false
a. When you define a type parameter like the A it gets erased after the compilation phase.
This means that the compiler uses type parameters to check that you use the correct types, but the resulting bytecode retains no information of A.
This also implies that you cannot use A as a real class in code but only as a "type reference", because at runtime this information is lost.
b & c. traits cannot define constructor parameters or auxiliary constructors by definition, they're also abstract by definition.
What you can do is define a trait body that gets called upon instantiation of the concrete implementation
One alternative solution is to define a Cloneable typeclass. For more on this you can find lots of blogs on the subject, but I have no suggestion for a specific one.
scalaz has a huge part built using this pattern, maybe you can find inspiration there: you can look at Order, Equal or Show to get the gist of it.