Scala error : unbound placeholder parameter and pattern matching condition - scala

I'm trying to combine pattern matching and condition, but this code (that's a Samza task):
override def process(incomingMessageEnvelope: IncomingMessageEnvelope, messageCollector: MessageCollector, taskCoordinator: TaskCoordinator): Unit = {
val event = (incomingMessageEnvelope getMessage).asInstanceOf[Map[String, Date]]
val symbol = (event get "symbol").asInstanceOf[String]
val eventDate = (event get "date").asInstanceOf[Date]
(store get symbol) match {
case x: java.util.Date if x.equals(eventDate) || x.after(eventDate) => _
case _ => {
this.store.put(symbol, eventDate)
}
}
}
returns this error:
Error:(30, 38) unbound placeholder parameter
case x if isGreaterOf(x, x) => _
^
Have you any idea of the error?
Thank you
Regards
Gianluca

The Exception does not match your code, but there is one line, that would throw the same error:
case x: java.util.Date if x.equals(eventDate) || x.after(eventDate) => _
because _ is a placeholder that can be used in patterns for matching and return types. It cannot not be used to indicate a Unit return value. To return a Unit value without executing code, you could just do
case x: java.util.Date if x.equals(eventDate) || x.after(eventDate) => ()
instead.

Related

scala variable number by name parameters [duplicate]

This question already has answers here:
Scala variable argument list with call-by-name possible?
(2 answers)
Closed 6 years ago.
I am trying to implement a control flow structure which can accept a variable number of by-name parameters.
See CalculateGroup method and its use.
I was trying to follow this post, but still have some issues
As I can see from the error, I suspect I need to define a type annotation predicate in CalculateGroup function?
Here is current code:
def compare[T : Numeric](x: T)(y: T) : Boolean = implicitly[Numeric[T]].gt( x, y )
val items = compare[Double](10) _
val assertionsEnabled = true
def Calculate( predicate: => Boolean ) =
if (assertionsEnabled && !predicate)
throw new AssertionError
Calculate{
items(5)
}
def CalculateGroup( list: (predicate: => Boolean) *) =
{
list.foreach( (p : (predicate: => Boolean) ) => {
if (assertionsEnabled && !predicate)
throw new AssertionError
})
}
CalculateGroup{
items(5),
items(3),
items(8)
}
Error details:
scala ControlFlow.scala
/Users/pavel/Documents/ControlFlow/ControlFlow.scala:36: error: ')' expected but ':' found.
def CalculateGroup( list: (predicate: => Boolean) *) =
^
/Users/pavel/Documents/ControlFlow/ControlFlow.scala:68: error: ')' expected but '}' found.
}
^
two errors found
You cannot use by-name var args, you could use a lazy collection like Iterator or maybe Stream:
def compare[T : Numeric](x: T)(y: T) : Boolean = implicitly[Numeric[T]].gt( x, y )
val items = compare[Double](10) _
val assertionsEnabled = true
def Calculate(predicate: => Boolean) =
if (assertionsEnabled && !predicate)
throw new AssertionError
Calculate{
items(5)
}
def CalculateGroup(list: Iterator[Boolean]) =
{
list.foreach { (p : Boolean ) =>
if (assertionsEnabled && !p) {
throw new AssertionError
}
}
}
CalculateGroup{Iterator(
items(5),
items(3),
items(8)
)}
You have a syntax problem... you are placing a colon in front of the word predicate in the signature of the method CalculateGroup and in the foreach. Just remove them and it should compile.
just remove it and know that the word predicate is not alias for a variable, but it should be the name of a class. So it's better if you capitalize it. Contrary to the case of your methods, which shouldn't be capitalized.
Update
To have multiple by-name parameters just do this:
def CalculateGroup( list: (=> Boolean) *) =
{
list.foreach( (p : (=> Boolean) ) => {
if (assertionsEnabled && !p)
throw new AssertionError
})
}

Type Mismatch in scala case match

Trying to create multiple dataframes in a single foreach, using spark, as below
I get values delivery and click out of row.getAs("type"), when I try to print them.
val check = eachrec.foreach(recrd => recrd.map(row => {
row.getAs("type") match {
case "delivery" => val delivery_data = delivery(row.get(0).toString,row.get(1).toString)
case "click" => val click_data = delivery(row.get(0).toString,row.get(1).toString)
case _ => "not sure if this impacts"
}})
)
but getting below error:
Error:(41, 14) type mismatch; found : String("delivery") required: Nothing
case "delivery" => val delivery_data = delivery(row.get(0).toString,row.get(1).toString)
^
My plan is to create dataframe using todf() once I create these individual delivery objects referenced by delivery_data and click_data by:
delivery_data.toDF() and click_data.toDF().
Please provide any clue regarding the error above (in match case).
How can I create two df's using todf() in val check?
val declarations make your first 2 cases return type to be unit, but in the third case you return a String
for instance, here the z type was inferred by the compiler, Unit:
def x = {
val z: Unit = 3 match {
case 2 => val a = 2
case _ => val b = 3
}
}
I think you need to cast this match clause to String.
row.getAs("type").toString

Reading input throws compile error

Pretty new to scala. I have this function:
def retrieveValue(valueName:String) : Double = {
for (ln <- io.Source.stdin.getLines) {
val parseResult = parseValue(ln)
parseResult match {
case Right(x) => return x
case Left(error) => println(error.message + " Please try again.")
}
}
}
And I'm getting this compile error:
QuadSolver.scala:14: error: type mismatch;
found : Unit
required: Double
for (ln <- io.Source.stdin.getLines) {
What exactly am I doing wrong?
parseResult match {
case Right(x) => x //note that `return` keyword is not needed
case Left(error) => println(error.message + " Please try again.") //returns Unit
}
This piece of code return either a Double or a Unit (Unit provided by println), therefore compiler expecting a Double as method's return type obviously complains.
In functional programming, it's better to have each function strictly following Single-Responsibility Principle.
Thus, you should have one function aiming to retrieve the value and one to print the result.

Scala: if statement returning Any instead of Unit in a closure [duplicate]

This question already has answers here:
What is return type of `if` statement
(3 answers)
Closed 8 years ago.
I have the following code in a method:
aSides.foreach(as => as.side.terr match
{
case r: TerrSRiver => paintSeq :+= ((g: Graphics2D) =>
{
g.setPaintColour(ColourInt.blue)
g.fill(Polygon(as.paintStd(0.2)))
}
case _: TerrSCoast => paintSeq :+= ((g: Graphics2D) =>
{
g.setPaintColour(TerrSea.colour)
g.fill(Polygon(as.paintStd(0.2)))
}) //one case excluded for simplicity
paintSeq is declared outside the method
var paintSeq: Seq[Graphics2D => Unit] = Nil
This compiles and runs as expected. However if I add an if Statement to the first case:
case r: TerrSRiver => paintSeq :+= ((g: Graphics2D) =>
{
g.setPaintColour(ColourInt.blue)
g.fill(Polygon(as.paintStd(0.2)))
if (zoom > 50) g.setPaintColour(ColourInt.white)
}
I get an error:
type mismatch; found : Seq[swing.Graphics2D => Any] required: Seq[swing.Graphics2D => Unit] AreaESw.scala /prStratSw/src/pGrid/pUISw line 49 Scala Problem
The error refers to the paintSeq :+= method. Why is the if statement returning Any rather than Unit? I can get rid of the error by adding a line after the if statement:
val dummy = 0
However if I add in return Unit at the end:
case r: TerrSRiver => paintSeq :+= ((g: Graphics2D) =>
{
g.setPaintColour(ColourInt.blue)
g.fill(Polygon(as.paintStd(0.2)))
if (zoom > 50) g.setPaintColour(ColourInt.white)
return Unit
}
It Compiles with the following warning:
enclosing method setVisObjs has result type Unit: return value discarded
But when it runs I get the following error
Exception in thread "AWT-EventQueue-0" scala.runtime.NonLocalReturnControl$mcV$sp
Using "return ()" still gives the run time exception.
This is Scala Swing code, but I'm using Scala 2.10.3 in the JavaFx Eclipse download: 4.2.2 on Linux.
Type of if
The result type of if (cond) expr is the common base type of expr and Unit, just like if (cond) { expr } else { () }
See What is return type of if statement? for details.
How to get Unit
To get an instance of type Unit you should use () literal:
if (zoom > 50) g.setPaintColour(ColourInt.white)
()
Unit value is the companion object of type Unit. It's not an instance of type Unit. Type of object Unit is Unit.type.
Do not use return in lambda
The result of lambda is the result of the last statement in lambda body, so you could just add result value (in this case literal ()) as the last line.
return in lambda will return from the surrounding method rather than from the lambda itself using exception (NonLocalReturnControl).
It's useful for java-style methods like this:
def firstNegative(seq: Seq[Int]): Option[Int] = {
for {
i <- seq
} if (i < 0) return Some(i)
return None
}
if (i < 0) return Some(i) here is lambda body. Equivalent code for this method:
def firstNegative(seq: Seq[Int]): Option[Int] = {
seq.foreach{ i =>
if (i < 0) return Some(i)
}
return None
}
You should have a else clause :
if (zoom > 50) g.setPaintColour(ColourInt.white) else ...
Benoit

How to use Box with Java null values

I use a Java method that returns an object or null if a value was not found. So I need to check for null values:
val value = javaobject.findThing(xyz)
if(value != null) {
value.doAnotherThing()
} else {
warn("Value not found.")
}
Can I write this code shorter with the Box concept? I have read the Lift-Wiki-documentation about the Box concept, but I don't understand how to use it with Java null values.
#TimN is right, you could use Box(value) to create a Box from a possibly null value, but you'll get a deprecation warning.
scala> val v: Thing = null
v: Thing = null
scala> Box[Thing](v)
<console>:25: warning: method apply in trait BoxTrait is deprecated: Use legacyNullTest
Box[Thing](v)
While you could use Box.legacyNullTest, if this is what you're doing, then I would just stick with the standard library and use Option.
Option(javaobject.findThing(xyz)) match {
case Some(thing) => thing.doAnotherThing()
case _ => warn("Value not found.")
}
And if you needed a Box to pass around, Option will automagically convert to a Box:
scala> val b: Box[Thing] = Option(v)
b: net.liftweb.common.Box[Thing] = Empty
Similar to Scala's Option, you can simply call Box() and pass in the value that may or may not be null, and you'll get a Box object that can be used normally. For example:
Box(javaobject.findThing(xyz)) match {
case Full(thing) => thing.doAnotherThing()
case _ => warn("Value not found.")
}
You can use Box.legacyNullTest. This method encapsulates any object in a Box in a null-safe manner:
def legacyNullTest[T](in: T): Box[T] = in match {
case null => Empty
case _ => Full(in)
}
Box returned from legacyNullTest can be later used as usual in for comprehensions or in pattern matching:
for {
fragment <- Box.legacyNullTest(uri.getFragment)
yield {
doSth(fragment)
}
or
Box.legacyNullTest(uri.getFragment) match {
case Full(fragment) =>
doSth(fragment)
case _ =>
log.error("Missing fragment part")
doSthElse
}