Reputation: 1860
I'm quite new to Scala (2.8) and here's something that I'm struggling to express in Scala:
I need to define a class that (due to interoperability with a Java library) implements Comparable; its generic type has to be Comparable with itself or a superclass
I also need to have a no-args constructor along with another that makes use of the generic parameter
I wrote a simple equivalent of what I'm trying to get in Java:
public class MyComparable<T extends Comparable<? super T>>{
public MyComparable() {}
public MyComparable(T a){
System.out.println(a);
}
}
I can import without any problem this class in the scala REPL and instantiate it.
This is what I'm writing in Scala to try to accomplish the same thing:
import java.lang.Comparable
class MyComparable[T <: Comparable[_>:Tb],Tb]()(implicit ev: T=:=Tb) {
def this(a: T) = {
this()
println(a)
}
}
I tried both by using the no-args constructor as the default one, or using the one with the T argument: in both cases I get error: could not find implicit value for parameter ev: =:=[T,Tb]
at line 5
Afaik, =:= is imported by default from scala.Predef (and in fact, this code works fine with only one constructor)
Upvotes: 2
Views: 1197
Reputation: 1860
This still isn't the same as the Java code I posted, but it seems to be close enough and cleaner than the other solutions:
import java.lang.Comparable
class MyComparable[T <: Comparable[T]]() {
def this(a: Comparable[_ >: T]) = {
this()
println(a)
}
}
Here's a bunch of miscellaneous links I read since when I got stuck with this problem, that may help someone else with a similar problem:
When is @uncheckedVariance needed in Scala, and why is it used in GenericTraversableTemplate?
to understand what does =:= really do
http://programming-scala.labs.oreilly.com/ch12.html#VarianceUnderInheritance
http://www.scala-lang.org/node/129
Type erasure and other low-level details of the Java generics
http://www.scala-lang.org/node/124
http://scalada.blogspot.com/2008/01/existential-types.html
http://lamp.epfl.ch/~emir/bqbase/2007/06/13/existentials.html
Upvotes: 2
Reputation: 297155
You are over-complicating the issue -- though it would be nice if Java had declaration-site variance, which would make all of this moot. Anyway, here's the equivalent code:
class MyComparable[T <: Comparable[T2], T2 >: T]() {
def this(a: T) = {
this()
println(a)
}
}
Granted that this does not use raw type, and has two type parameters instead of one. Then again, there's the question of what you are actually trying to accomplish with that declaration. I wonder if what you actually want isn't this:
import scala.annotation.unchecked.uncheckedVariance
class MyComparable[-T <: Comparable[T @uncheckedVariance]]() {
def this(a: T) = {
this()
println(a)
}
}
I tell Scala to ignore variance above at my peril, because I assume Comparable
can, indeed, be contra-variant. The following code indicates that's indeed the case:
scala> trait Cp[-T] {
| def compareTo(other: T): Int
| }
defined trait Cp
scala> class MyComparable[-T <: Cp[T]] {
| }
defined class MyComparable
Upvotes: 3
Reputation: 2829
Not entirely certain what you're trying to do, but you can do it like this:
import java.lang.Comparable
class MyComparable[T <: Comparable[_>:Tb],Tb]()(implicit ev: T=:=Tb) {
def this(a: T)(implicit ev: T=:=Tb) = {
this()
println(a)
}
}
Upvotes: 3