- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Why isn't Ordered[T] contravariant in T?
Wed, 2009-10-07, 18:51
I am just writing an exam and find, to my dismay, that my nifty
problem is falling apart because Ordered[T] isn't Ordered[-T], as I
had assumed it to be. In fact, not so long ago it was apparently
covariant! Huh?
The Java API is littered with Comparable<? super T> so that I can, for
example, pass a java.sql.Date into a method that wants a Comparable.
(java.sql.Date <: java.util.Date <: Comparable).
In Scala, how do I express this? Let's say Person extends
Ordered[Person] and Employee extends Person. I want to pass Employee
objects into a function min[T <: Ordered[T]](a : T, b: T). It doesn't
work: Employee isn't a subtype of Ordered[Employee].
If Ordered was contravariant, then a call min(empl1, empl2) would work
(Employee <: Person <: Ordered[Person] <: Ordered[Employee]). Don't
believe me? Run the code below.
Some Googling leads me to this:
http://osdir.com/ml/lang.scala/2007-03/msg00194.html where someone
named Martin said "After some experimenting followed by some thinking,
I'm now convinced that Ordered should be contravariant." Well, duh...
So, again, here are my questions:
1) Why isn't Ordered[T] contravariant in T?
2) How do I write a method in Scala that accepts the equivalent of
Comparable<? super T?
Thanks,
Cay
-----------------------------------------
object Main {
trait GoodOrdered[-T] {
def compareTo(other : T) : int
}
class Person(var id : String, var name : String) extends GoodOrdered[Person] {
override def compareTo(other : Person) = id.compareTo(other.id)
}
class Employee(id : String, name : String, var salary : Double)
extends Person(id, name)
def min[T <: GoodOrdered[T]](a : T, b : T) = {
if (a.compareTo(b) < 0) a else b
}
def main(args : Array[String]) {
println(min(new Employee("007", "James Bond", 100000), new
Employee("M", "M", 200000)))
}
}
Wed, 2009-10-07, 19:17
#2
Re: Why isn't Ordered[T] contravariant in T?
On Wed, Oct 07, 2009 at 11:01:39AM -0700, Randall R Schulz wrote:
> I believe this is one of those things that changing fundamentally in
> 2.8, by the way.
Yeah, Ordering isn't contravariant either. I realized when I attempted
to make it so a while ago that methods like this:
def max(x: T, y: T): T = if (gteq(x, y)) x else y
put the kibosh on anything but invariance.
This could change, things could be restructured, invariant and
co/contravariant bits could be separated out, but I doubt it's super
high on anyone's list.
Wed, 2009-10-07, 19:27
#3
Re: Why isn't Ordered[T] contravariant in T?
On Wednesday October 7 2009, Randall R Schulz wrote:
> On Wednesday October 7 2009, Cay Horstmann wrote:
> > ...
> >
> > So, again, here are my questions:
> >
> > 1) Why isn't Ordered[T] contravariant in T?
> > 2) How do I write a method in Scala that accepts the equivalent of
> > Comparable<? super T?
>
> You can side-step this issue by using a generic implicit conversion
> ...
By the way, the implicit part is not essential, only the generic part.
Randall Schulz
Wed, 2009-10-07, 19:57
#4
Re: Why isn't Ordered[T] contravariant in T?
Hmm... this works:
trait Ordering[-T] {
def compare(x: T, y: T): Int
def max[S <: T](x: S, y: S): S = if (compare(x, y) <= 0) x else y
}
--j
On Wed, Oct 7, 2009 at 11:13 AM, Paul Phillips <paulp@improving.org> wrote:
trait Ordering[-T] {
def compare(x: T, y: T): Int
def max[S <: T](x: S, y: S): S = if (compare(x, y) <= 0) x else y
}
--j
On Wed, Oct 7, 2009 at 11:13 AM, Paul Phillips <paulp@improving.org> wrote:
On Wed, Oct 07, 2009 at 11:01:39AM -0700, Randall R Schulz wrote:
> I believe this is one of those things that changing fundamentally in
> 2.8, by the way.
Yeah, Ordering isn't contravariant either. I realized when I attempted
to make it so a while ago that methods like this:
def max(x: T, y: T): T = if (gteq(x, y)) x else y
put the kibosh on anything but invariance.
This could change, things could be restructured, invariant and
co/contravariant bits could be separated out, but I doubt it's super
high on anyone's list.
--
Paul Phillips | Appreciation is a wonderful thing; it makes what is
Future Perfect | excellent in others belong to us as well.
Empiricist | -- Voltaire
slap pi uphill! |----------* http://www.improving.org/paulp/ *----------
Wed, 2009-10-07, 20:07
#5
Re: Why isn't Ordered[T] contravariant in T?
Of course, then Ordering can't extend java.util.Comparator.
--j
On Wed, Oct 7, 2009 at 11:51 AM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
--j
On Wed, Oct 7, 2009 at 11:51 AM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
Hmm... this works:
trait Ordering[-T] {
def compare(x: T, y: T): Int
def max[S <: T](x: S, y: S): S = if (compare(x, y) <= 0) x else y
}
--j
On Wed, Oct 7, 2009 at 11:13 AM, Paul Phillips <paulp@improving.org> wrote:
On Wed, Oct 07, 2009 at 11:01:39AM -0700, Randall R Schulz wrote:
> I believe this is one of those things that changing fundamentally in
> 2.8, by the way.
Yeah, Ordering isn't contravariant either. I realized when I attempted
to make it so a while ago that methods like this:
def max(x: T, y: T): T = if (gteq(x, y)) x else y
put the kibosh on anything but invariance.
This could change, things could be restructured, invariant and
co/contravariant bits could be separated out, but I doubt it's super
high on anyone's list.
--
Paul Phillips | Appreciation is a wonderful thing; it makes what is
Future Perfect | excellent in others belong to us as well.
Empiricist | -- Voltaire
slap pi uphill! |----------* http://www.improving.org/paulp/ *----------
Thu, 2009-10-08, 03:57
#6
Re: Why isn't Ordered[T] contravariant in T?
This works:
trait Ordered[T] { def compare( t:T): Int;}class A( val id:Int)class B( override val id:Int) extends A(id)
object Main { def min[T <% Ordered[T]]( x:T, y:T):T= if( x.compare( y)<0) x else y;
implicit def getOrdered[T<:A]( x:T):Ordered[T]= { new Ordered[T]{ def compare( other:T)= x.id-other.id; } }
def main( args:Array[String]) { println( min( new A(3), new A(2)).id); // prints 2 println( min( new B(5), new B(6)).id); // prints 5 }}
Sergio Hayashi
On Wed, Oct 7, 2009 at 2:55 PM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
trait Ordered[T] { def compare( t:T): Int;}class A( val id:Int)class B( override val id:Int) extends A(id)
object Main { def min[T <% Ordered[T]]( x:T, y:T):T= if( x.compare( y)<0) x else y;
implicit def getOrdered[T<:A]( x:T):Ordered[T]= { new Ordered[T]{ def compare( other:T)= x.id-other.id; } }
def main( args:Array[String]) { println( min( new A(3), new A(2)).id); // prints 2 println( min( new B(5), new B(6)).id); // prints 5 }}
Sergio Hayashi
On Wed, Oct 7, 2009 at 2:55 PM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
Of course, then Ordering can't extend java.util.Comparator.
--j
On Wed, Oct 7, 2009 at 11:51 AM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
Hmm... this works:
trait Ordering[-T] {
def compare(x: T, y: T): Int
def max[S <: T](x: S, y: S): S = if (compare(x, y) <= 0) x else y
}
--j
On Wed, Oct 7, 2009 at 11:13 AM, Paul Phillips <paulp@improving.org> wrote:
On Wed, Oct 07, 2009 at 11:01:39AM -0700, Randall R Schulz wrote:
> I believe this is one of those things that changing fundamentally in
> 2.8, by the way.
Yeah, Ordering isn't contravariant either. I realized when I attempted
to make it so a while ago that methods like this:
def max(x: T, y: T): T = if (gteq(x, y)) x else y
put the kibosh on anything but invariance.
This could change, things could be restructured, invariant and
co/contravariant bits could be separated out, but I doubt it's super
high on anyone's list.
--
Paul Phillips | Appreciation is a wonderful thing; it makes what is
Future Perfect | excellent in others belong to us as well.
Empiricist | -- Voltaire
slap pi uphill! |----------* http://www.improving.org/paulp/ *----------
Thu, 2009-10-08, 05:37
#7
Re: Why isn't Ordered[T] contravariant in T?
Oh, I never noticed that Ordered extends j.u.Comparator. Thanks, that
answers my first question.
I think there are two different issues
1) How to interact with j.u.Comparator and the Java classes that implement it
2) How to do the right thing for Scala
As for 2), it seems to me that Scala needs a contravariant Ordered[-T]
type (maybe with a different name or in a different package). It's the
right thing to do.
1) seems a hard problem. Making programmers write all these
conversions doesn't seem right. It sure would be nice if one could
specify the variance of imported Java classes. Something like
import java.util.Comparator[-T]
IIRC, the class file has sufficient information to check the position rules.
On Wed, Oct 7, 2009 at 11:55 AM, Jorge Ortiz wrote:
> Of course, then Ordering can't extend java.util.Comparator.
>
> --j
>
> On Wed, Oct 7, 2009 at 11:51 AM, Jorge Ortiz wrote:
>>
>> Hmm... this works:
>>
>> trait Ordering[-T] {
>> def compare(x: T, y: T): Int
>> def max[S <: T](x: S, y: S): S = if (compare(x, y) <= 0) x else y
>> }
>>
>> --j
>>
>> On Wed, Oct 7, 2009 at 11:13 AM, Paul Phillips
>> wrote:
>>>
>>> On Wed, Oct 07, 2009 at 11:01:39AM -0700, Randall R Schulz wrote:
>>> > I believe this is one of those things that changing fundamentally in
>>> > 2.8, by the way.
>>>
>>> Yeah, Ordering isn't contravariant either. I realized when I attempted
>>> to make it so a while ago that methods like this:
>>>
>>> def max(x: T, y: T): T = if (gteq(x, y)) x else y
>>>
>>> put the kibosh on anything but invariance.
>>>
>>> This could change, things could be restructured, invariant and
>>> co/contravariant bits could be separated out, but I doubt it's super
>>> high on anyone's list.
>>>
>>> --
>>> Paul Phillips | Appreciation is a wonderful thing; it makes what is
>>> Future Perfect | excellent in others belong to us as well.
>>> Empiricist | -- Voltaire
>>> slap pi uphill! |----------* http://www.improving.org/paulp/
>>> *----------
>>
>
>
On Wednesday October 7 2009, Cay Horstmann wrote:
> I am just writing an exam and find, to my dismay, that my nifty
> problem is falling apart because Ordered[T] isn't Ordered[-T], as I
> had assumed it to be. In fact, not so long ago it was apparently
> covariant! Huh?
>
> ...
>
> So, again, here are my questions:
>
> 1) Why isn't Ordered[T] contravariant in T?
> 2) How do I write a method in Scala that accepts the equivalent of
> Comparable<? super T?
You can side-step this issue by using a generic implicit conversion form
the (most general / widest) type you have to Ordered[TheTypeYouHave]
using that most general type as the upper bound on the type parameter.
E.g.
implicit
def
ancestor2ordered[A <: Ancestor](a: A): Ordered[A] =
new Ordered[A] {
def compare(other: A): Int = { /* ordering logic */ }
I believe this is one of those things that changing fundamentally in
2.8, by the way.
> Thanks,
>
> Cay
Randall Schulz