Gap in the concept of implicit Ordering of a type used to create a Collection - scala

Forgive me if the solution to this problem is too obvious or has been resolved already in this forum earlier (in which case, please point me to the post).
I have a class
org.personal.exercises.LengthContentsPair (l: Int, c: String)
{
val length = l
val contents = c
}
Then, in the same source file, I also define an implicit value which defines the way objects
of this type is to be ordered, thus:
object LengthContentsPair {
implicit val lengthContentsPairOrdering = new Ordering [LengthContentsPair] {
def compare (a: LengthContentsPair, b: LengthContentsPair)= {
a.length compare b.length;
}
}
}
following solutions given in this forum.
Now, I want to create a specialized Set which limits the number of elements in the Set to a given number. So, I define a separate class like this:
import scala.collection.immutable.TreeSet;
import org.personal.exercises.LengthContentsPair.lengthContentsPairOrdering;
class FixedSizedSortedSet [LengthContentsPair] extends TreeSet [LengthContentsPair]
{ ..
}
To me, this seems the correct way to subclass a TreeSet. But, the compiler throws the following error:
(1) No implicit Ordering defined for LengthContentsPair.
(2) not enough arguments for constructor TreeSet: (implicit ordering: Ordering[LengthContentsPair])scala.collection.immutable.TreeSet[LengthContentsPair]. Unspecified value parameter ordering.
Have I understood the scoping rules wrongly? It is something quite easy I feel, but I cannot put my hand on it.

You have defined FixedSizedSortedSet wrong. Your implementation has generic type parameter named LengthContentsPair which has nothing to do with your class with that name. In other words, you have shadowed LengthContentsPair class with generic type.
If you need a specialized set that only holds elements of LengthContentsPair, then you probably meant:
class FixedSizedSortedSet extends TreeSet[LengthContentsPair]
{ ..
}
This should work if an instance of Ordering[LengthContentsPair] is visible. But this shouldn't be a problem, since the ordering is defined in companion object of LengthContentsPair and is visible as implicit parameter by default.
But if you rather need a generic extension of TreeSet which can hold elements of any type, then you probably meant this:
class FixedSizedSortedSet[T](implicit ordering: Ordering[T]) extends TreeSet[T]
{ ..
}
Implicit parameter is needed because TreeSet requires an implicit Ordering[T], so we need to forward that requirement to FixedSizedSortedSet
BTW. I'd suggest you to consider replacing your LengthContentsPair class with a case class.

Related

Scala get classtag from class instance

I need to write a generic method to get all fields of an object and it's value, the class of this object may contains ClassTag, so we should find a way to get it as well, is any way good way ? the difficulty is we don't know the class ahead, it may contains ClassTag (zero to many), It may not.
For example,
class A(x : Int) {}
a = new A(1)
We should output x => 1
class B[T: ClassTag]() {}
b = new B[Float]()
We should output _$1 = Float
def fields(obj: AnyRef) = obj.getClass.getDeclaredFields.map(field => (field.getName, field.get(obj))
will give you an array of pairs of field names and corresponding values, which you can massage into the format you want. You can test for types and do something depending on whether you have a ClassTag or not.
But for your specific examples: neither x in A nor the ClassTag in B are fields, they are just constructor parameters which aren't stored anywhere in the instance. To change this, you can declare it as a val:
class A(private val x: Int)
class B[T]()(private val tag: ClassTag[T])
or make sure they are used somewhere in the body outside the constructor.

Inheriting type parameter classes in Scala

I have one abstract class with type parameter and few its implementations:
abstract class AbstractClass[T] {
def func: T
}
class DoubleClass extends AbstractClass[Double]{
def func = 0.0
}
and then I want to create a function that takes some sequence of such objects:
def someFunc(objs: Iterable[AbstractClass]) = objs.foreach(obj=>println(obj.func))
but it says "Class AbstractClass takes type parameters"
I am new at scala and definitely doing something wrong, but i can`t figure out what
It should in most cases be def someFunc[A](objs: Iterable[AbstractClass[A]]). In particular, this allows return type to depend on A, e.g.
def someFunc[A](objs: Iterable[AbstractClass[A]]) = objs.map(_.func)
returns Iterable[A].
Sometimes you may actually want to allow mixing AbstractClasses with different parameters. E.g. in your example you just print func, which can always be done. In this case, as Sascha Kolberg's answer says, use a wildcard:
def someFunc(objs: Iterable[AbstractClass[_]])
But if you find yourself using wildcards constantly, consider rethinking your design.
The simple solution would be to add the wildcard type as type argument to AbstractClass in your function:
def someFunc(objs: Iterable[AbstractClass[_]]) = objs.foreach(obj=>println(obj.func))
This way objs can be an iterable containing any kind of AbstractClass, so essentially a mixed type collection.
If you want to be sure, that the iterable argument of someFunc holds only instances of one implementation of AbstractClass[_], you can add another type parameter to someFunc:
def someFunc[A <: AbstractClass[_]](objs: Iterable[A]) = objs.foreach(obj=>println(obj.func))
<: is a type bound that basically says that A is a subclass of AbstractClass[_]

Can structural typing work with generics?

I have an interface defined using a structural type like this:
trait Foo {
def collection: {
def apply(a: Int) : String
def values() : collection.Iterable[String]
}
}
}
I wanted to have one of the implementers of this interface do so using a standard mutable HashMap:
class Bar {
val collection: HashMap[Int, String] = HashMap[Int, String]()
}
It compiles, but at runtime I get a NoSuchMethod exception when referring a Bar instance through a Foo typed variable. Dumping out the object's methods via reflection I see that the HashMap's apply method takes an Object due to type erasure, and there's some crazily renamed generated apply method that does take an int. Is there a way to make generics work with structural types? Note in this particular case I was able to solve my problem using an actual trait instead of a structural type and that is overall much cleaner.
Short answer is that the apply method parameter is causing you grief because it requires some implicit conversions of the parameter (Int => Integer). Implicits are resolved at compile time, the NoSuchMethodException is likely a result of these missing implicits.
Attempt to use the values method and it should work since there are no implicits being used.
I've attempted to find a way to make this example work but have had no success so far.

Scala class that handles enumerations generically

I want to create a generic class that holds the value of an enumeration, and also allows access to the possible values of the enumeration. Think of a property editor for example - you need to know the current value of the property, and you also need to be able to know what other values are legal for the property. And the type of enumeration should not be known in advance, you should be able to work with any kind of enumeration.
My first thought was something like this:
class EnumerationProperty[T <: Enumeration](value:T)
However, that doesn't work because for enumerations T isn't a type, it's an object. Other variations I have tried are:
class EnumerationProperty[T <: Enumeration](value:T.Value)
class EnumerationProperty[T <: Enumeration.Value](value:T)
(I won't go into the details of why these don't work because I suspect the reasons aren't interesting.)
For first part of your question. You can define holder for generic enum value like this:
case class EnumerationProperty[T <: Enumeration#Value](value:T)
But I don't know how to get all enum values without explicitly pass Enumeration object. Enumeration has values() method to get all values. And Enumeration#Value has link to Enumeration, but with private access
In your use case (a property editor) I think the best solution is to rely on scala reflection available in scala 2.10. Given a class's TypeTag, you can get the full type (without erasure) of all of its members plus their values, and from that populate your property editor. For enumerations, use the TypeTag to get their values using the following method:
Using Scala 2.10 reflection how can I list the values of Enumeration?
Now, maybe you don't want or can't use scala reflection, and from now on I'll suppose this is the case. If that is true then you are opening a whole can of worm :)
TL;DR: This is not possible using a standard Enumeration, so you'll probably have to explcitly wrap the enumeration values as shown in Ptharien's Flame's answer (or roll your own fork of Enumeration). Below I detail all my attempts, please bear with me.
Unfortunately, and for some unknown reason to me (though I suspect it has to do with serialization issues), Enumeration.Value has no field pointing to its Enumeration instance. Given how Enumeration is implemented, this would be trivial to implement, but of course wehave no say, short of forking Enumeration and modifying our version (which is actually what I did for this very purpose, plus to add proper support for serialization and reflection - but I diggress).
If we can't modify Enumeration, maybe we can just extend it? Looking at the implementation again, something like this would seem to work:
class EnumerationEx extends Enumeration {
protected class ValEx(i: Int, name: String) extends Val(i, name) {
#transient val enum: Enumeration = EnumerationEx.this
}
override protected def Value(i: Int, name: String): Value = new ValEx(i, name)
}
object Colors extends EnumerationEx {
val Red, Green, Blue = Value
}
The downside would be that it only works for enumerations that explicitly extend EnumerationEx instead of Enumeration, but it would be better than nothing.
Unfortunately, this does not compile simply because def Value ... is declared final in Enumeration so there is no way to override it. (Note again that forking Enumeration would allow to circunvent this. Actually, why not do it, as we are already down the path of using a custom Enumeration anwyay. I'll let you judge).
So here is another take on it:
class EnumerationEx extends Enumeration {
class ValueWithEnum( inner: Value ) {
#transient val enum: Enumeration = EnumerationEx.this
}
implicit def valueToValue( value: Value ): ValueWithEnum = new ValueWithEnum( value )
}
And indeed it works as expected. Or so it seems.
scala> object Colors extends EnumerationEx {
| val Red, Green, Blue = Value
| }
defined module Colors
scala> val red = Colors.Red
red: Colors.Value = Red
scala> red.enum.values
res58: Enumeration#ValueSet = Colors.ValueSet(Red, Green, Blue)
Hooray? Well no, because the conversion from Value to ValueWithEnum is done only when accessing red.enum, not at the time of instantiation of the Colors enumeration. In other words, when calling enum the compiler needs to know the exact static type of the enumeration (the compiler must statically know that red's type is Colors.Value, and not just Enumeration# Value). And in the use case you mention (a property editor) you can only rely to java reflection (I already assumed that you won't use scala reflection) to get the type of an enumeration value, and java reflection will only give you Enumeration#Val (which extends Enumeration#Value) as the type of Colors.Red. So basically you are stuck here.
Your best bet is definitly to use scala reflection in the first place.
class EnumProps[E <: Enumeration](val e: E)(init: e.Value) {...}
Then you can use e and e.Value to implement the class.

covariant type T occurs in invariant position

I'm moving my first steps in Scala and I would like to make the following code works:
trait Gene[+T] {
val gene: Array[T]
}
The error that the compiler gives is: covariant type T occurs in invariant position in type => Array[T] of value gene
I know I could do something like:
trait Gene[+T] {
def gene[U >: T]: Array[U]
}
but this doesn't solve the problem because I need a value: pratically what I'm trying to say is "I don't care of the inside type, I know that genes will have a gene field that return its content". (the +T here is because I wanna do something like type Genome = Array[Gene[Any]] and then use it as a wrapper against the single gene classes so I can have a heterogeneous array type)
Is it possible to do it in Scala or I'm simply taking a wrong approach? Would it be better to use a different structure, like a Scala native covariant class?
Thanks in advance!
P.S.: I've also tried with class and abstract class instead than trait but always same results!
EDIT: with kind suggestion by Didier Dupont I came to this code:
package object ga {
class Gene[+T](val gene: Vector[T]){
def apply(idx: Int) = gene(idx)
override def toString() = gene.toString
}
implicit def toGene[T](a: Vector[T]) = new Gene(a)
type Genome = Array[Gene[Any]]
}
package test
import ga._
object Test {
def main(args: Array[String]) {
val g = Vector(1, 3, 4)
val g2 = Vector("a", "b")
val genome1: Genome = Array(g, g2)
println("Genome")
for(gene <- genome1) println(gene.gene)
}
}
So I now think I can put and retrieve data in different types and use them with all type checking goodies!
Array is invariant because you can write in it.
Suppose you do
val typed = new Gene[String]
val untyped : Gene[Any] = typed // covariance would allow that
untyped.gene(0) = new Date(...)
this would crash (the array in your instance is an Array[String] and will not accept a Date). Which is why the compiler prevents that.
From there, it depends very much on what you intend to do with Gene. You could use a covariant type instead of Array (you may consider Vector), but that will prevent user to mutate the content, if this was what you intended. You may also have an Array inside the class, provided it is decladed private [this] (which will make it quite hard to mutate the content too). If you want the client to be allowed to mutate the content of a Gene, it will probably not be possible to make Gene covariant.
The type of gene needs to be covariant in its type parameter. For that to be possible, you have to choose an immutable data structure, for example list. But you can use any data structure from the scala.collection.immutable package.