Why can't _ be used inside of string interpolation? - scala

This works
(x => s"$x")
but this
(s"${_}")
results in
[error] ...: unbound placeholder parameter
[error] (s"${_}")
Is this a case of leaky abstraction?
Furthermore: (s"$_") fails with a completely different output:
[error] ...: invalid string interpolation: `$$', `$'ident or `$'BlockExpr expected
[error] (s"$_")
[error] ^
[error] ...: unclosed string literal
[error] (s"$_")

Calling string interpolation a leaky abstraction is totally right in my opinion. While it works fine in most cases, there are many edge cases where it just doesn't work the way how one expects it. This one is another incarnation of such an edge case.
I don't know why s"$_" is not accepted by the compiler. Some time ago there were a pull request that introduced this syntax for pattern matching: PR 2823
Interestingly this PR also contains test cases that test that the underscore outside of a pattern match produces an error.
Unfortunately there is no further description why this is implemented the way it is implemented.
Som Snytt, the guy who implemented the PR is active on SO, hopefully he can tell more.

Related

Why does usage of Option.get gives a compile error

I want to filter out options which are not defined in a sequence and create sequence without Options(with the actual value). I am trying to compile the following code in scala :
val idLibId = idOptionalLibId.filter(idOptionalLibId => idOptionalLibId._2.isDefined)
.map(idLibId => idLibId._1 -> idLibId._2.get)
idOptionalLibId is Seq of tuples.
But it gives me the follownig error:
[error] MandatoryApprovalOverride.scala:27:55: Use of Option.get
[error] .map(idLibId => (idLibId._1 -> idLibId._2.get))
[error]
Anyone had similar problem?
Calling .get on an Option is dangerous because it will throw if the value is None. You know that you've filtered all the None values out but the compiler doesn't.
Wouldn't this be a better way to do it?
val idLibId = idOptionalLibId.collect{case (k,Some(v)) => k -> v}
The only reason this would be an error is due to settings of your particular project, e.g. a combination of WartRemover to warn on Option.get and -Xfatal-warnings to turn all warnings into errors. You can see https://www.wartremover.org/doc/warts.html for motivation:
scala.Option has a get method which will throw if the value is None. The program should be refactored to use scala.Option#fold to explicitly handle both the Some and None cases.
and likely other cases where you'll run into similar warnings/errors (depending on WartRemover configuration in your project).
Though in this case the fix proposed by #jwvh is better than fold or getOrElse.

spark example wont compile

Trying to run one of apache sparks example codes (https://github.com/apache/spark/blob/master/examples/src/main/scala/org/apache/spark/examples/graphx/AggregateMessagesExample.scala) I get the following compile error
too many arguments for method sendToDst: (msg: (Int, Double))Unit
[error] Error occurred in an application involving default arguments.
[error] triplet.sendToDst(1, triplet.srcAttr)
[error] ^
[error] one error found
But looking at the mehtods it seems to be correct. Not sure what is wrong here.
It looks like the method you are calling expects a single argument (a Tuple2) and you are passing in 2 arguments.
Try
triplet.sendToDst((1, triplet.srcAttr))

Problems with stubbing spy'ed object in scala

I have a pretty complex test where I decided to go with approach of partial stubbing of tested class. in my test I have something like this:
val srv = new Service()
val srvSpy = spy(srv)
doReturn(now).when(srvSpy).getRunDateInTimeZone(futureChecklist)
doReturn("boo").when(srvSpy).interpolateChecklistName("name", now)
val returnTuple = (createdChlRev, createdChl)
doReturn(returnTuple).when(srvSpy).create(fChlCreatorId,
fChlCreatorEmail,
"username",
true,
templateId,
"boo",
optDueDate)(connection)
val (chlRev, chl) = srv.createFromFutureChecklist(futureChecklist)(connection)
In the code above, the first two stubbed methods working as expected. However, the last one throws an error:
[error] Tuple2 cannot be returned by create$default$8() [error]
create$default$8() should return JsObject [error] *** [error] If
you're unsure why you're getting above error read on. [error] Due
to the nature of the syntax above problem might occur because: [error]
1. This exception might occur in wrongly written multi-threaded tests. [error] Please refer to Mockito FAQ on limitations of
concurrency testing. [error] 2. A spy is stubbed using
when(spy.foo()).then() syntax. It is safer to stub spies - [error]
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
I've trying bunch of different approached of stubbing and still getting the same error. At this point I have no idea even where to look.
What am I doing wrong?
Any advice would be helpful.
Thanks
Sorry, it was my own dumb mistake. I was stubbing the spied class, but calling the original one :(
Thanks,

Why need a blank line after process(aString)! in scala?

When I run an external process, looks like we need to add a blank line after the calling. Why it throws that error?
class JobActor extends Actor {
def receive = {
case msg:String =>
Process(msg)!
// here need a blank line, otherwise it throws error
sender ! "complete"
}
}
the error is
[error] found : akka.actor.ActorRef
[error] required: scala.sys.process.ProcessLogger
[error] sender ! "complete"
[error] ^
[error] one error found
You hit the exact reason of why postfix operators is a feature that generates a warning when you compile with the -feature flag.
Here's an extract that explains why such feature is still under discussion (emphasis added):
postfixOps. Only where enabled, postfix operator notation (expr op)
will be allowed. Why keep the feature? Several DSLs written in Scala
need the notation. Why control it? Postfix operators interact poorly
with semicolon inference. Most programmers avoid them for this reason.
(source)
Process defines two methods
abstract def !: Int
abstract def !(log: ProcessLogger): Int
When you do
Process(msg)!
you mean to call the former, but since there's no unambiguous indication that the line should end (i.e. that a semicolon should be inferred), the parser starts reading the next line, it finds something can can syntactically be an argument (sender) and you end up calling the second version of ! instead.
The resulting code is actually:
Process(msg)! sender ! "complete"
i.e.
(Process(msg).!(sender)).!("complete")
hence the error: sender is not an instance of ProcessLogger.
In order to fix it, you have to untangle the ambiguity yourself. There's many ways of doing it, the simplest one being to avoid the postfix operator altogether:
Process(msg).!
sender ! "complete"
Actually, given this other question of yours, you can even just do
msg.!
sender ! "complete"
This could be another case where Scala's grammar does not allow for postfix operators in any other place than the end of an expression.
The first one was described in "Why does this code need an empty line or a semicolon?"
Adding a semi-colon might also make the code compile, because of the semicolon inference.
Process(msg)!;
sender ! "complete"

Adding Strings to an Array out of a List in a Scala template

I have a List of Objects and want to iterate every Element in this List to get their Id Strings. Those Strings must be saved into another List. I always get this Compiler Error:
[error] FilePath:line:64: illegal start of simple expression
[error] #var formNameList : Array[String] = new Array[String](formList.size())
[error] ^
[error] File Path:69: ')' expected but '}' found.
[error] }
[error] ^
[error] two errors found
[error] (compile:compile) Compilation failed
[error] Total time: 3 s, completed 05.12.2013 14:03:37
So please guys help, before I drive insane.
My Code:
#var formNameList : Array[String] = new Array[String](formList.size())
#for(i <- 0 until formList.size()) {
#formNameList.add(formList.get(i).getFormId())
}
#views.html.formmanager.showresults(formNameList, formManager)
Im a Newbie in Scala and this is a very simple Task in Java but Scala is such a tough language. Its also very hard to read: What does this .:::, ::: or this <++= mean?
Short answer:
#views.html.formmanager.showresults(formList.map(_.getFormId).toArray, formManager)
Long answer:
Scala templates are templates - they should be used to generate some presentation of data and not be used as placeholders for a general code. I would strongly advice against doing any mutable or complex computations inside of templates. If you have complex code you should either pass it as a parameter or create a helper object like this:
# in helper.scala:
object Helper {
def toArrayOfIds(formList:List[Form]) = formList.map(_.getFormId).toArray
}
# in view.scala.html:
#Helper.toArrayOfIds(formList)
Another thing - prefer List to an Array. Usually I never use Array in my scala programms. Also notice the use of higher order function map instead of creating array an manually populating it. This is highly recommended. Just see how short the first example is.
.:::, ::: <++= could mean different things in different contexts. Usually first two operators mean the same thing which is concatenation of two lists. You can read about this in the "Programming in Scala" by Martin Odersky, first edition is available for free.
And if you need to introduce new variable in the template you can do it like this:
#defining(user.firstName + " " + user.lastName) { fullName =>
<div>Hello #fullName</div>
}
see play documentation