Bare generics and inheritance

120 views
Skip to first unread message

Sarah Gerweck

unread,
Apr 16, 2013, 8:36:17 PM4/16/13
to scala...@googlegroups.com
I'm working on a project and seem to have found a bug in the Scala compiler that makes it impossible to implement certain interfaces. Anybody have any thoughts on what to do about this short of dropping into Java? I am just trying to implement an interface from a third-party library. I have a reduced case below, but this is an actual issue I'm running into in a real project that needs to deal with less-than-perfect APIs.

Suppose that you have the following Java class:

  public interface Cmp extends Comparable { }

Although this may generate a "bare generics" warning in Java 5 and above, this is valid code for every version of Java since Comparable was added in 1.2. However, I run into endless troubles when I try to implement Cmp (or anything that extends Cmp) in Scala.

This should be very straightforward.

scala> new Cmp { def compareTo(x: AnyRef): Int = 0 }
<console>:8: error: object creation impossible, since method compareTo in trait Comparable of type (x$1: T)Int is not defined
(Note that T does not match AnyRef)

Hmm, maybe if I match the Java signature exactly:

scala> new Cmp { def compareTo(x: java.lang.Object): Int = 0 }
<console>:8: error: object creation impossible, since method compareTo in trait Comparable of type (x$1: T)Int is not defined
(Note that T does not match Object)

That doesn't work, and Any doesn't work either, so let's try to give it wants even though it makes absolutely no sense:

scala> new Cmp { def compareTo(x: T): Int = 0 }
<console>:8: error: not found: type T
              new Cmp { def compareTo(x: T): Int = 0 }

Maybe I can override the missing type?

scala> new Comparable[AnyRef] with Cmp { def compareTo(x: AnyRef): Int = 0 }
<console>:8: error: illegal inheritance;
 anonymous class $anon inherits different type instances of trait Comparable:
Comparable[T] and Comparable[AnyRef]
              new Comparable[AnyRef] with Cmp { def compareTo(x: AnyRef): Int = 0 }

scala> new Comparable[_] with Cmp { def compareTo(x: AnyRef): Int = 0 }
<console>:8: error: class type required but Comparable[_] found
              new Comparable[_] with Cmp { def compareTo(x: AnyRef): Int = 0 }

It seems pretty clear that this is a bug, and I will open one. That said, does anybody have any other suggestions on how to work around this? Short of building a modified version of that interface just for compile time, my only other thought is that maybe I can use dynamic methods, which would be pretty silly.

Thanks! Sarah

Seth Tisue

unread,
Apr 16, 2013, 9:06:51 PM4/16/13
to scala...@googlegroups.com

Sarah Gerweck

unread,
Apr 16, 2013, 10:44:54 PM4/16/13
to scala...@googlegroups.com
Thanks for pointing these out, though I have to say I'm a bit disappointed that the response often seems to be "it's not even worth trying to be compatible with Java." So many of Scala's flaws seem to have been caused by trying to be compatible with Java to start with.

Som Snytt

unread,
Apr 16, 2013, 11:02:29 PM4/16/13
to Sarah Gerweck, scala-user
On Tue, Apr 16, 2013 at 5:36 PM, Sarah Gerweck <sarah...@gmail.com> wrote:

 Short of building a modified version of that interface just for compile time....



That's pretty short.

Naftalin and Wadler's generics book shows a generified Observable just for compile time.  Arguably, even if Scala supported the raw type, it's better to work around it.

I just tried out this case, and it works like the proverbial charm.  The hard part is deleting the class file and making sure you never package it in a release jar.

// delete me after compilation
package jcmp {
  trait Cmp[A] extends java.lang.Comparable[A]
}



You inspired me to try other things that you tried, but I like my error better:

self-type app.MyCmp does not conform to Comparable[Object]'s selftype Comparable[Object]

The compiler withholds just enough information to remain cryptic.  However, the spec says that both "self-type" and "selftype" are misspellings.

Som Snytt

unread,
Apr 16, 2013, 11:15:31 PM4/16/13
to Sarah Gerweck, scala-user

> "it's not even worth trying to be compatible with Java."

There's binary compatibility versus source compatibility versus the sort of compatibility tested for here

http://similarminds.com/compatibility-bigfive.html
and here
http://divorcecourt.com/divorce-court-resource-articles/dc-compatibility-test/

This is actually really helpful.

One exercise: "List five things you don’t like about your intended programming language; List five things that are wrong with you?"

> "self-type" and "selftype"

I bet if I read the spec carefully, it will tell me that these are not actually the same thing.



--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Sarah Gerweck

unread,
Apr 17, 2013, 12:07:17 AM4/17/13
to scala...@googlegroups.com, Sarah Gerweck

> "it's not even worth trying to be compatible with Java."

There's binary compatibility versus source compatibility versus the sort of compatibility tested for here

I mean compatibility in the sense that Scala advertises:

"In particular, the interaction with the mainstream object-oriented Java programming language is as smooth as possible. Scala has the same compilation model (separate compilation, dynamic class loading) like Java and allows access to thousands of existing high-quality libraries."
 
I've come across countless articles, blogs and talks that advocate Scala as drop-in compatible with Java, that you can seamlessly call one from the other, etc. Having used Scala in several large projects, it seems like I've found dozens of ways that this is not really true. In practice, it seems more like Scala can call Java, but Java can only call Scala if things are very simple and clean.

This isn't an unreasonable stance, but it falls far short of the dream of a modern language for the JVM that's transparently compatible with all the technology that's been developed over the years. I can't help but be a little sad when I see comments that suggest that this kind of compatibility isn't even really a goal. There are lots of open– and closed-source libraries out there that haven't been rewritten for Java 5 and that don't really need to be rewritten. Based on the code review boards I've sat on, I'd bet that 30% of Java classes that targeted Java 5+ from their inception don't properly use generic types where they should.

But this is pretty far sidetracked from my actual question, and I don't want to dwell on Perfect when Scala is already Very Good (I would claim Best for a lot of situations).

It seems that there's no workaround for my issue, so I'll go ahead with looking at the workarounds. (Sadly, building a compile-only interface is not a trivial thing in my case, because it's actually a bunch of interfaces in a tree, many of which were written before Java 5 and that won't have any other real benefits from parametrization where they haven't already been upgraded.)

One exercise: "List five things you don’t like about your intended programming language; List five things that are wrong with you?"

None of the things that are wrong with me have anything to do with programming. :-) 

Simon Ochsenreither

unread,
Apr 19, 2013, 9:00:21 AM4/19/13
to scala...@googlegroups.com, Sarah Gerweck

Scala has the same compilation model (separate compilation, dynamic class loading) like Java and allows access to thousands of existing high-quality libraries.

One could argue that exactly this is the case here ... raw types are certainly not “high quality” code. :-)

Anyway, I feel your pain, but dragging along Java's cruft can be a huge cost and in this case the cost isn't worth the benefits. Additionally, Sun/Oracle have reserved the right to make raw types illegal in future versions of javac.

Adriaan Moors

unread,
May 21, 2013, 5:57:26 PM5/21/13
to scala...@googlegroups.com
I'd like to qualify this statement a bit to "it's not worth the [enormous effort] trying to be compatible with Java [when it comes to dealing with inheriting raw types]".

We definitely try to be compatible with Java as much as we can. We also spent a lot of time trying to support raw types (the main reason we have existentials in Scala),
but raw types have proved extremely tricky to shoe-horn into Scala's type system. The problem with inheritance from raw types in Scala is -- as you've discovered -- that you'd have to introduce a class-scoped synthetic existential for each omitted type argument to your raw parent type, and then use the corresponding existential everywhere. 

It's possible, just a lot of work and we thus prioritized it as "not worth it" (relatively speaking).
We're open to re-prioritizing given enough incentive, so please vote/comment on these issues.
Reply all
Reply to author
Forward
0 new messages