Reading input throws compile error - scala

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.

Related

dynamic string interpolation

I would like to pretty-print a Product, such as a case class, so I create the following trait:
trait X extends Product {
def fmtStrs =
productIterator map {
case _ : Double => "%8.2f"
case _ => "%4s"
} map (_ + separator) toSeq
override def toString = {
new StringContext("" +: fmtStrs : _*) f (productIterator.toSeq : _*)
}
}
This uses string interpolation as described in the ScalaDoc for StringContext.
But this won't compile, with this cryptic error:
Error:(69, 70) too many arguments for interpolated string
new StringContext("" +: fmtStrs : _*) f (productIterator.toSeq : _*)
Is this a bug, or limitation of a macro? Note that doing the following works fine, so I suspect this may be related to the variable argument list:
scala> val str2 = StringContext("","%4s,","%8.2f").f(1,23.4)
str2: String = " 1, 23.40"
The reason f is a macro is so that it can give you an error when types of format specifiers and arguments don't match, and this isn't possible to check by looking at ("" +: fmtStrs : _*) and (productIterator.toSeq : _*), so it isn't particularly surprising this doesn't work. The error message could be clearer, so let's see what exactly happens.
If you look at the implementation of f (it took me some time to actually find it, I finally did by searching for the error message), you'll see
c.macroApplication match {
//case q"$_(..$parts).f(..$args)" =>
case Applied(Select(Apply(_, parts), _), _, argss) =>
val args = argss.flatten
def badlyInvoked = (parts.length != args.length + 1) && truly {
def because(s: String) = s"too $s arguments for interpolated string"
val (p, msg) =
if (parts.length == 0) (c.prefix.tree.pos, "there are no parts")
else if (args.length + 1 < parts.length)
(if (args.isEmpty) c.enclosingPosition else args.last.pos, because("few"))
else (args(parts.length-1).pos, because("many"))
c.abort(p, msg)
}
if (badlyInvoked) c.macroApplication else interpolated(parts, args)
With your call you have a single tree in both parts and argss, and parts.length != args.length + 1 is true, so badlyInvoked is true.
s doesn't care what its arguments look like, so it's just a method and your scenario works.

Why scala cannot infer common return type for a function with multiple parameter lists?

Scala can infer the common base of the two parameters to a function, T = Option[Int] is found from Some[Int] and None:
def handleUndefined1[T](op: => T, alt: => T) : T = {
try { op }
catch { case _: Exception => alt }
}
val x = handleUndefined1(Some(1),None) // Option[Int]
But as a partial function:
def handleUndefined2[T](op: => T)(alt: => T) : T = {
try { op }
catch { case _: Exception => alt }
}
// None is not Some[Int]
val x = handleUndefined2(Some(1))(None)
First, it's not a "partial function" what you're doing is called a "curried function."
Second, try the following:
val x = handleUndefined1(Some(1), _)
and see what happens. You'll get a warning saying that you're missing a type parameter on the 2nd parameter. Why?
The type inferencer goes from left to right. Generally, types in the first argument group will determine those in the 2nd, 3rd, etc. If you leave out a type parameter, the inferencer will not be able to determine the type it should become as you've left out information.
Use Option rather than Some:
val x = handleUndefined2(Option(1))(None)
Alternatively you can coerce the Some to Option:
val x = handleUndefined2(Some(1): Option[Int])(None)
Generally it's a good idea to always use Option rather than Some for this reason.

Scala error : unbound placeholder parameter and pattern matching condition

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.

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

for comprehensions with if guard

How do I use for comprehensions with if guard?
type Error = String
type Success = String
def csrfValidation(session:Session, body:JsValue):Either[Error,Success] = {
val csrfRet = for (csrfSession <- csrfStateSessionValidation(session).right;
csrfReq <- csrfStateReqBodyValidation(body).right if (csrfSession == csrfReq)) yield (csrfReq)
if (csrfRet.isRight)
Right(csrfRet)
else {
Logger.warn("request and session csrf is not the same")
Left("Oops,something went wrong, request and session csrf is not the same")
}
}
I got this error when using it.
'withFilter' method does not yet exist on scala.util.Either.RightProjection[Error,Success], using `filter' method instead
EDIT:
I got another error. I think it returns an option result when if guard is used.
[error] type mismatch;
[error] found : Option[scala.util.Either[Nothing,controllers.ProfileApiV1.Success]]
[error] required: scala.util.Either[?,?]
[error] csrfReq <- csrfStateReqBodyValidation(body).right if (csrfSession == csrfReq)) yield (csrfReq)
EDIT2
This is what I did to fix above error. I also move if-guard to later process.
val result = for {
foo <- Right[String,String]("teststring").right
bar <- Right[String,String]("teststring").right
} yield (foo, bar)
result fold (
ex => Left("Operation failed with " + ex),
v => v match {
case (x,y) =>
if (x == y) Right(x)
else Left("value is different")
}
)
I believe what you are seeing is a compiler warning and not an actual error. The RightProjection does not support withFilter which is what is "preferred" (but not yet required) for a guard condition, so plain old filter is used instead. As to the difference to these functions and why this came about, check out the link below for an explanation.
http://scala-programming-language.1934581.n4.nabble.com/Rethinking-filter-td2009215.html#a2009218
Add either a semi-colon or a new line just before the if.