Why need a blank line after process(aString)! in scala? - 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"

Related

What does "!" mean in scala?

I am looking at a piece of code with the following:
graph.vertices.filter(!_._2._1)
I understand that _ are wildcard characters in scala but I do not know what the ! is supposed to do.
What does ! mean in scala?
Scala doesn't have operators at the syntax level. All operations are methods.
For example, there is no add operator in the syntax, but numbers have a + method:
2.+(3) // result is 5
When you write 2 + 3, that's actually syntax sugar for the expression above.
Any type can define a unary_! method, which is what !something gets desugared to. Booleans implement it, with the obvious meaning of logical negation ("not") that the exclamation mark has in other languages with C heritage.
In your question, the expression is an abbreviated form of the following call:
graph.vertices.filter { t => !(t._2._1) }
where t is a tuple-of-tuples, for which the first element of the second element has a type that implements unary_! and (as required by .filter) returns a Boolean. I would bet the money in my pocket that the element itself is a Boolean, in which case ! just means "not."
As Robert said, ! is a method name. It can be tricky determining which ! method is being used. For example, in the line of code:
val exitValue = command.!(ProcessLogger(stdoutWriter.println, stderrWriter.println))
where command is a String (or Seq), command can be implicitly converted to a ProcessBuilder, so its ! method would apply. Your IDE may be able to help. IntelliJ IDEA Ultimate was able to tell me where ! was defined.

Scala illegal start of simple expression with postfix function

I am playing around with calling external command from Scala. Here is a stripped out example of what I am working on:
import scala.sys.process._
object Testing {
def main(args: Array[String]) {
val command = "ls"
val result = command!
if (result != 0) { // <---- illegal start of simple expression
println("Error")
return
}
}
}
I am getting a compile error: illegal start of simple expression for the line with the if statement. I can fix it with a new line:
val result = command!
// Add a line
if (result != 0) {
My suspicion is that it has something to do with the ! postfix function, but it was my understanding that superfluous lines/whitespaces shouldn't make a difference to the compiler.
You need to explicitly enable postfix expressions:
1) Importing the flag locally: import scala.language.postfixOps
2) or adding the flag to the project itself: scalacOptions += "-language:postfixOps"
The above link in the comment from #Łukasz contains lots of info about this feature. Also, see http://docs.scala-lang.org/style/method-invocation.html in the "Suffix Notation" section for your exact use case.
EDIT: maybe it was not clear enough, but as #Łukasz pointed in comments, importing/enabling postfix expressions doesn't make your code compile. It just avoids the compiler warning. Your code won't compile because the semicolons are optional and the compiler is treating the ! operator as infix, and thus taking elements from the next line for the expressions. This is exactly what the documentation in the link above states with exactly this same example:
This style is unsafe, and should not be used. Since semicolons are
optional, the compiler will attempt to treat it as an infix method if
it can, potentially taking a term from the next line.
names toList
val answer = 42 // will not compile!
This may result in unexpected compile errors at best, and happily
compiled faulty code at worst. Although the syntax is used by some
DSLs, it should be considered deprecated, and avoided.

How to resolve ambiguous method reference in scala

Here is the specific issue I am encountering. I am using SLF4J Logger (The type of the variable logger below)
//After adding to a map
logger debug ("Adding {} = {}", key, value)
Here is what mouse hover in eclipse (and the compiler) tell me.
ambiguous reference to overloaded definition, both method debug in trait Logger of type (x$1: String, x$2: Object*)Unit and method debug in trait Logger of type (x$1: String, x$2: Any, x$3: Any)Unit match argument types (String,String,String)
I understand why they are ambiguous. I am certainly not arguing with the compiler :). I want to simply know how seasoned programmers solve this issue.
Here are the alternatives I can use
Create and array , and ride the Object* definition
logger debug ("Adding {} = {}", Array(key, value):_*)
Cast to Any
logger debug ("Adding {} = {}", key.asInstanceOf[Any], value.asInstanceOf[Any])
Neither approach is particularly appealing. Does the community have a better approach or suggestions for me?
Many thanks!
I would use
logger.debug("Adding {} = {}", key, value: Any)
Alternatively following can be used:
logger.debug("Adding {} = {}", Array(key, value):_*)
Please pay attention to :_*. Should you omit these symbols and it will call Object* method providing only 1 argument, which will be an array.
First off a nod of credit to #Shadowlands, #ArneClaassen and #OlgeRudenko.
As mentioned in the comments, this does seem to be known issue. That stopped me from trying to "solve" it. The next thing to do was to find a good work around that did not break Scala idioms.
With these constraints in mind I chose to go with String Interpolation as suggested above. I also switched to scala-logging. Quoting from their GitHub/README,
Scala Logging is a convenient and performant logging library wrapping SLF4J. It's convenient, because you can simply call log methods without checking whether the respective log level is enabled:
logger.debug(s"Some $expensive message!")
It's performant, because thanks to Scala macros the check-enabled-idiom is applied, just like writing this more involved code:
if (logger.isDebugEnabled) logger.debug(s"Some $expensive message!")
Thanks all! As far as I am concerned, this is resolved. If the commentators can post their answers, I will be happy to acknowledge them.
As always, feels good to be standing on the shoulders of friendly giants!
PS: I just verified that there is no execution cost to String interpolation if you are using scala-logging. My verification method was crude but effective.
log.debug{
{
throw new IllegalAccessException("This should not have been called with debug off!")
}
s"Added Header ${name}:${headerValue}"
}
Sure enough, when I set my log to DEBUG, the exception is thrown, as expected , but vanishes when I set it to a level higher.
And yes, I have already removed the IllegalAccessException part :).

What are the rules to govern underscore to define anonymous function?

I am using _ as placeholder for creating anonymous function, and the problem is I cannot predict how Scala is going to transform my code. More precisely, it mistakenly determines how "large" the anonymous function I want.
List(1,2,3) foreach println(_:Int) //error !
List(1,2,3) foreach (println(_:Int)) //work
List(1,2,3) foreach(println(_:Int)) //work
Using -Xprint:typer I can see Scala transforms the first one into "a big anonymous function":
x$1 => List(1,2,3) foreach(println(x$1:Int))
the worked 2th 3th are right transformation into what I want.
... foreach (x$1 => println(x$1:Int))
Why this? What's the rule ?
Simple rules to determine the scope of underscore:
If the underscore is an argument to a method, then the scope will be outside that method, otherwise respective the rules below;
If the underscore is inside an expression delimited by () or {}, the innermost such delimiter that contains the underscore will be used;
All other things being equal, the largest expression possible will be used.
So, by the rule #1, instead of println((x: Int) => x), the scope will be placed outside (including) println.
By rule #2, the latter two examples will have the function delimited by parenthesis, so (x => println(x: Int)).
By rule #3, the first example will be the whole expression, as there are no delimiting parenthesis.
I believe Mr. Sobral's answer is incorrect. The actual rules can be found in Scala Language Reference, section 6.23, subhead "Placeholder Syntax for Anonymous Functions."
The only rule is that the innermost expression that properly contains the underscore defines the scope of the anonymous function. That means that Mr. Sobral's first two rules are correct, because a method call is an expression and parenthesizing an expression doesn't change its meaning. But the third rule is the opposite of the truth: all other things being equal, the smallest expression that makes sense will be used.
Unfortunately, my explanation for the behavior Mr. Laskowski observed for his first example is a bit involved and speculative. When
List(1,2,3) foreach println(_:Int)
is typed at the Scala read-eval-print loop. The error message is:
error: type mismatch;
found : Unit
required: Int => ?
List(1,2,3) foreach println(_:Int)
^
If you vary the example a tiny bit:
List(1,2,3).foreach println(_:Int)
the error message is easier to make sense of --
error: missing arguments for method foreach in class List;
follow this method with `_' if you want to treat it as a partially applied function
List(1,2,3).foreach println(_:Int)
^
To understand things a little better, call scala thus: scala -Xprint:parser, which, after every expression is typed by the user, causes the expression as fleshed out by the parser to be printed. (Along with a lot of garbage, which I'll omit.) For Laskowski's first example, the expression understood by the parser is
((x$1: Int) => List(1, 2, 3).foreach(println((x$1: Int))))
For the second example, the parser's version is
((x$1: Int) => List(1, 2, 3).foreach.println((x$1: Int)))
Apparently the scope rule is applied before the expression structure has been fully fleshed out. In both cases, the parser guesses that the smallest expression starts at List, even though once the parens are inserted that's no longer true. In the second example, in addition to that assumption it assumes that, because println is an identifier, foreach println is a chain of methods, the first having no arguments. The error at foreach is then caught before the error at println, masking it. The error at println is that its result is Unit, and foreach requires a function. Once you see the parse tree, it's easy to see that this is correct, but it's not clear (to me) why the parse tree is what it is.

dsl for capturing field name

I'm working on a mapper and wanted a typesafe way to capture class fieldnames for mapping and went with a syntax I'd used in C#:
case class Person(name: String, age: Int)
new Mapping[Person]() {
field(_.age).name("person_age").colType[java.lang.Integer]
field(_.name).name("person_name")
}
where def field(m: T => Unit): FieldMap
This triggers the following warnings:
Warning:(97, 13) a pure expression does nothing in statement position; you may be omitting necessary parentheses
field(_.age).name("person_age").colType[java.lang.Integer]
^
Warning:(98, 13) a pure expression does nothing in statement position; you may be omitting necessary parentheses
field(_.name).name("person_name")
^
So clearly that's not a desirable syntax. Any way I can tweak the signature of field to avoid the warning or is there a more idiomatic scala way of mapping fields in a typesafe manner?
Note: #sjrd's answer indeed gets rid of the warning, but the attempted feature doesn't seem feasible with scala reflection after all. My end goal is a Mapper that allows the specifying of T members in a compile time checked mannner, rather than strings, so it's less vulnerable to typo's and refactoring issues.
The field method takes a T => Unit function as parameter. Hence, the lambda _.age, which is equivalent to x => x.age, is typechecked as returning Unit. The compiler warns that you are using a pure expression (x.age) in statement position (expected type Unit), which basically means that the expression is useless, and might as well be removed.
There is a very simple symptomatic solution to your problem: replace m: T => Unit by m: T => Any. Now your expression x.age is not in statement position anymore, and the compiler is happy.
But your code suggests that there is something wrong a little bit deeper, since you obviously don't use the result of m anywhere. Why is m for anyway?