Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic Scala Errors That Make No Sense

Tags:

java

types

scala

I'm trying to get a function to compile/work in scala, and getting several absolutely inane error messages that I just can't make sense of. If I write my code like this:

def checkUniqueReviewNumber(number: String): Boolean = {
    val qc = new QualityClient
    if(review.isEmpty)
      false
    else {
      val qrList = qc.listInPL(Vars.currentPLId.get.get,null,null,null,null,null,null,false,false,CurrentUser.getUser.key).qualityReviews
      !qrList.exists(qr:QualityReview => qr.reviewNumber == number)
    }
  }

I get the error:

.../QualityReviewCreate.scala:189: error: not found: type ==
   [scalac]       !qrList.exists(qr:QualityReview => qr.reviewNumber == number)

And if I write the code more like this:

def checkUniqueReviewNumber(number: String): Boolean = {
    val qc = new QualityClient
    if(review.isEmpty)
      false
    else {
      val qrList = qc.listInPL(Vars.currentPLId.get.get,null,null,null,null,null,null,false,false,CurrentUser.getUser.key).qualityReviews
      !qrList.exists(qr:QualityReview => qr.reviewNumber.equals(number))
    }
  }

I get the errors:

... /QualityReviewCreate.scala:189: error: ')' expected but '(' found.
   [scalac]       !qrList.exists(qr:QualityReview => qr.reviewNumber.equals(number))
   [scalac]                                                                ^
    ... /QualityReviewCreate.scala:189: error: ';' expected but ')' found.
   [scalac]       !qrList.exists(qr:QualityReview => qr.reviewNumber.equals(number))
   [scalac]                                                                        ^
   [scalac] two errors found

The types involved may be contributing here, but if so I'm absolutely confused as to why. qrList should be a java ArrayList of QualityReview, which is a java object with a java String field called reviewNumber.

Does anyone understand what's going on here?

like image 957
Ian Avatar asked Jun 20 '11 22:06

Ian


1 Answers

The problem is that Scala's parsing for anonymous functions with explicit argument types is ambiguous, and sometimes that leads to some very strange quirks. This is one of them. Take the following expression:

(qr:QualityReview => qr.reviewNumber == number)

Scala is (apparently) parsing this as follows:

(qr:(QualityReview => qr.reviewNumber == number))

This isn't what you wanted. In fact, it's not even an anonymous function. Desugaring the expression yields the following:

(qr: Function1[QualityReview, ==[qr.reviewNumber, number]])

So in other words, we are ascribing a type to qr, where that type is given by Function1 parameterized with QualityReview and the type given by == parameterized by the types qr.reviewNumber and number. All of this is valid Scala, and I suspect none of it is what you intended.

The error comes about when Scala goes looking for a type with name ==, which of course it doesn't find (it could exist, but it doesn't). If it had gotten past that error, it would have quickly run into issues finding types qr.reviewNumber and number.

There are a couple ways to avoid this issue. In general, I would just recommend using a slightly different style when declaring your functions. The Scala Style Guide is a good place to start. In the case of this function, the easiest way to fix the problem is to drop the type annotation (QualityReview). You could also solve the problem by putting parentheses around qr:QualityReview. Also, I think a space after the colon might fix the issue, though I can't be sure. Finally, using curly braces rather than parentheses usually makes the compiler prefer interpreting => as a lambda delimiter rather than a type. I would have written your exists expression in the following way:

!(qrList exists { qr => qr.reviewNumber == number })

Actually, I probably would have used the underscore syntax, but that's an entirely different question. :-)

!(qrList exists { _.reviewNumber == number })
like image 189
Daniel Spiewak Avatar answered Nov 01 '22 23:11

Daniel Spiewak