7

I have a problem in using Drools Planner (written in Java) in Scala. One of interfaces in Drools planner is declared as:

public interface Score<S extends Score> extends Comparable<S>

However another interface uses 'Score' as a raw type:

public interface Solution {
    Score getScore();

Then I'd like to implement this interface in Scala:

class MySolution extends Solution {
    def getScore: Score = ...

And I get a compilation error: Scala compiler disallows writing just 'def getScore: Score'. When I try adding 'Score[_]' or 'Score[whatever]' compiler complains about type incompatibility. What should I do?

Geoffrey De Smet
  • 26,223
  • 11
  • 73
  • 120
iirekm
  • 8,890
  • 5
  • 36
  • 46
  • Can you also post the full text from the type compatibility error? – Kevin Wright Mar 12 '11 at 14:51
  • Interesting case. Adam Warski also posted a similar problem on the user mailing list. We should fix this in the Drools Planner source. I've created this issue to track it: https://issues.jboss.org/browse/JBRULES-2924 – Geoffrey De Smet Mar 12 '11 at 17:22
  • 1
    Thank you. However I would also expect some support from Scala on this. Drools Planner is probably not the only library with this issue. – iirekm Mar 12 '11 at 22:50
  • The developers of Drools Planner should fix their code. Related example that even Sun/Oracle does stupid stuff: http://lampsvn.epfl.ch/trac/scala/ticket/3634 – soc Mar 14 '11 at 09:56

4 Answers4

9

Write a Java class to serve as a bridge between what the Java interface requires and what Scala allows.

SolutionBridge.java:

abstract class SolutionBridge implements Solution {
    public Score getScore() {
        return scalaGetScore();
    }

    abstract Score<?> scalaGetScore();
}

SolutionScala.scala:

class SolutionScala extends SolutionBridge {
    def scalaGetScore() = null.asInstanceOf[Score[_]]
}
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • Yes, I've come to a similar idea, but it requires Java. I'd prefer to do this in Scala directly. – iirekm Mar 12 '11 at 22:48
  • @iirekm Yeah, well, no such luck. Note that raw types belong in the Java version that _precedes_ the last one to be EOLed. Java 1.4 is not among the JVM versions Scala supports. – Daniel C. Sobral Mar 12 '11 at 23:21
4

The error message which you omitted is not an extraneous detail. Re "I would also expect some support from Scala on this", you might also opt to participate in the process by reading the error messages and, if you don't understand them, include them when asking a question rather than vaguely paraphrasing them.

Error messages, they're important. Even when they're confusing. Especially when they're confusing.

Here is the error in 2.8.1:

a.scala:2: error: overriding method getScore in trait Solution of type ()Score[_ <: Score];
 method getScore has incompatible type
  def getScore: Score[_] = null
      ^
one error found

Here is the error with trunk:

a.scala:2: error: overriding method getScore in trait Solution of type ()Score[_ <: AnyRef];
 method getScore has incompatible type
  def getScore: Score[_] = null
      ^
one error found

There is a key difference there, which contributes to why it works with trunk when I do as the error message instructs me.

// this compiles with 2.9, but not with 2.8
class MySolution extends Solution {
  def getScore: Score[_ <: AnyRef] = null
}

The way the raw type Score is being used in the java source (as a type constructor in one location but with an implied existential type argument in another, with the second appearance bounding the first) it's a wonder it works anywhere. You don't want to know how much damage accomodating this sort of thing has already inflicted on the compiler. It's true that it would be nice if raw types just worked, but many things would be nice. Some things are not possible, some things are not desirable, and some things require too much effort from the tiny number of people keeping the ship afloat. Raw types win the triple crown.

psp
  • 12,138
  • 1
  • 41
  • 51
  • This damage is called backwards compatibility. Yes, it's not easy, but it's necessary to get wider adoption of Scala. – iirekm Mar 13 '11 at 09:16
  • Not even Java provides that level of backward compatibility you want. Sun/Oracle announced that support for raw types might be dropped in future versions of Java. Scala wasn't built to repeat all mistakes Java made. – soc Mar 14 '11 at 10:00
3

The next release of Drools Planner (5.2.0.M2) will fix this issue. Here's the commit on git.

In some cases, people want to define their own Score implementation (for example NurseRosterScore implements HardAndSoftScore), to be able to show to the user per hard or soft constraint type what exactly is violated in the best solution. This change is the first step to make that easier and cleaner (even though it's already possible).

Geoffrey De Smet
  • 26,223
  • 11
  • 73
  • 120
0

Have you tried to cast Score:

val s = solution.getScore.asInstanceOf[Score[Int]]
tenshi
  • 26,268
  • 8
  • 76
  • 90
  • This is not the issue: I don't have a 'solution' object yet. I get this problem when I try to implement 'MySolution extends Solution' – iirekm Mar 12 '11 at 22:52