Uses of _ in Scala - scala

I am new to Scala and was trying to understand where we can use underscore and where Scala prevents the use of underscore. I read through various posts but I am not able to completely understand the concept. I would appreciate any help on this. Thanks
Code:
object ScalaMainObj {
def main(args : Array[String])
{
val t1 = List(1,2,3,4)
//t1.foreach(println(_*2)) -> Will refer to this as Line1
//t1.foreach(_*2) -> Will refer to this as Line2
t1.foreach(x => println(x*2)) //-> Will refer to this as Line3
}
Question:
I am trying to understand why code in Line1 gives me an error while compiling. The error I get is "missing parameter type for expanded function ((x$1) ⇒ x$1.$times(2))"
Does the above statement indicate that scala is not able to resolve the return type of (x$1 * 2) function?
Since the code in Line2 is compiling, I believe that scala is able to resolve the type of '_'as Int. (Tried to replace * function with / function since "/" function is available to Int and not Strings)
Thanks again for any suggestions/explanations

Related

What type of FunctionN instance is created when creating anonymous function with no parameter in Scala

I wrote the below scala code in my IDE(IntelliJ) to create an anonymous function :
val hi = () => "Hi"
When I desugar my scala code , IDE gives me code like one below :
val hi: Function1[(), _root_.java.lang.String] = () => "Hi"
But it is giving error : '=>' expected but ',' found.
I am keen to know the Function type of the anonymous function.
I also want to know why the IDE is giving me this result which is actually throwing error.
As said by Luis, hi is a function of no input parameter that produces a String, thus its type is Function0[String].
If it was defined like this for instance it would be a Function1[String, String]:
val hi1 = (name: String) => s"Hi $name"

Scala ambiguity with paren-less function calls

Excuse the long set-up. This question relates to, but is not answered by, Scala: ambiguous reference to overloaded definition - best disambiguation? .
I'm pretty new to Scala, and one thing that's throwing me off is that Scala both:
Has first-class functions
Calls functions when using object-dot notation without any parenthetical argument lists (as if the function were a property)
These two language features are confusing me. Look at the below code:
class MyClass {
def something(in: String): String = {
in + "_X"
}
def something: String => String = {
case _ => "Fixed"
}
}
val my = new MyClass()
println(List("foo", "bar").map(my.something))
I would expect this to print List("foo_X", "bar_X") by calling the something prototype that matches the map's required String => ? argument. Instead, the output is List("Fixed", "Fixed") - Scala 2.11 is invoking the no-argument something() and then passing its return value to the map.
If we comment out the second no-argument prototype of something, the output changes to be the expected result, demonstrating that the other prototype is valid in context.
Adding an empty argument list to the second prototype (making it def something()) also changes the behavior.
Changing the my.something to my.something(_) wakes Scala up to the ambiguity it was silently ignoring before:
error: ambiguous reference to overloaded definition,
both method something in class MyClass of type => String => String
and method something in class MyClass of type (in: String)String
match argument types (String)
println(List("foo", "bar").map(my.something(_)))
Even using the supposedly-for-this-purpose magic trailing underscore doesn't work:
val myFun: (String) => String = my.something _
This results in:
error: type mismatch;
found : () => String => String
required: String => String
val myFun: (String) => String = my.something _
My questions:
If I have MyClass exactly as written (no changes to the prototypes, especially not adding an empty parameter list to one of the prototypes), how do I tell Scala, unambiguously, that I want the first one-argument version of something to pass as an argument to another call?
Since there are clearly two satisfying arguments that could be passed to map, why did the Scala compiler not report the ambiguity as an error?
Is there a way to disable Scala's behavior of (sometimes, not always) treating foo.bar as equivalent to foo.bar()?
I have filed a bug on the Scala issue tracker and the consensus seems to be that this behaviour is a bug. The compiler should have thrown an error about the ambiguous reference to "my.something".

Missing Parameter Type For Expanded Function

I am new to Scala and I am having trouble with an example from the book Scala in Action.
I am using IntelliJ, but I've also tried it as script (REPL). The scala compiler gives me the same error as IntelliJ. (I am using Scala 2.10, as the book suggest).
Here is my code:
def parseArgs(args: Array[String]): Map[String, List[String]] = {
val command = args.head
val params = parseArgs(args)
val url = args.last
def nameValuePair(paramName: String) = {
def values(commaSeparatedValues: String) = commaSeparatedValues.split(",").toList
// x => x + 2
val index = args.indexOf(_ == paramName)
(paramName, if(index == -1) Nil else values(args(index + 1)))
}
Map(nameValuePair("-d"), nameValuePair("-h"))
}
The message I get is:
C:\scala\projects\scripts\restclientscript.scala:12: error: missing parameter type for expanded function ((x$1) => x$1.$eq$eq(paramName))
val index = args.indexOf(_ == paramName)
^
one error found
This is exactly as it is shown in the book but I can't figure out how to make it work.
Also the method indexOf is actually findIndexOf in the book. But that method does not exist the compiler tells me (and the doc: http://www.scala-lang.org/api/2.10.3/index.html#scala.Array).
Lastly, IntelliJ will not accept the == inside the indexOf() method (highlighted red, but compiles).
Any help would be appreciated! :)
The book may be referring to an older version of Scala. Looking at the doc page you linked it is clear that the method indexOf has the following signature:
indexOf(elem: T): Int
That means that the method doesn't expect a closure but instead a value. You probably want to use indexWhere:
indexWhere(p: (T) ⇒ Boolean): Int
That should work!
One more advice is: never trust IntelliJ Idea errors, always double check them with sbt as Idea uses a different algorithm for checking errors and doesn't rely on the actual compiler.
Array.indexOf takes an instance for which the index should be found in the array.
If you want a version with predicate, there's Array.indexWhere (at least according to Scala 2.11 docs) which takes a predicate function p : (T) => Boolean.
So, you can either do:
args.indexOf(paramName)
or
args.indexWhere(_ == paramName)

Why the following scala code is valid?

My understanding is Unit = void, but why I can pass in multiple argument?
So can anyone explain why the following code is valid?
def foo(x: Unit) = println("foo")
foo("ss", 1)
If you run your snippet with scala -print you'll roughly get the following output for the code:
/* Definition of foo */
private def foo(x: scala.runtime.BoxedUnit): Unit = {
/* Invocation of foo */
foo({
new Tuple2("ss", scala.Int.box(1));
scala.runtime.BoxedUnit.UNIT
});
As you can see, the arguments to foo are rewritten into a code block that creates a tuple but then returns UNIT.
I can't see a good reason for this behaviour and I'd rather get a compiler error thrown instead.
A related question which gives a decent answer to this is here:
Scala: Why can I convert Int to Unit?
From Section 6.26.1 of the Scala Language Specification v2.9, "Value Discarding":
If e has some value type and the expected type is Unit, e is converted to the expected type by embedding it in the term { e; () }.
So, in your case it seems ("ss", 1) is being converted to a tuple so that it can be treated as a single argument, then as that argument type is not Unit, it is converted to a block which computes that tuple value then returns unit to match with the required type of the parameter.

Scala-IDE or Scala unjustified syntax ambiguity

I am learning Scala with Scala-IDE in Eclipse. While following the Chapter 9: Control Abstraction, part 1: Reducing Code Duplication in the Programming in Scala book, I have written the code from the book (fully represented below), it worked fine! When I started removing the unnecessary blank lines, a strange thing happened. Here is the entire code before the removal of the blank lines in the filterFiles() method:
object Code_c09s01_ControlAbstraction extends App{
object FilesFilter {
private def filterFiles(path: String, pattern: String, matcher: (String, String) => Boolean) = {
val files = (new java.io.File(path)) listFiles
for(file <- files if matcher(file.getName, pattern)) yield file
}
def filterExtension(path: String, pattern: String) = filterFiles(path, pattern, _.endsWith(_))
def filterName(path: String, pattern: String) = filterFiles(path, pattern, _.contains(_))
def filterRegex(path: String, pattern: String) = filterFiles(path, pattern, _.matches(_))
}
def printArray[A](message: String, arr: Array[A]) {
println (message)
println (arr mkString("\n"))
}
def test() {
val path = "C:\\";
printArray("--- filtering by ext: ---", FilesFilter.filterExtension(path, ".txt"))
printArray("--- filtering by containment: ---", FilesFilter.filterName(path, "1"))
printArray("--- filtering by regex: ---", FilesFilter.filterRegex(path, "."))
}
test
}
which works just fine! However, after removing the blank lines from the filterFiles() method, the method now looks like this:
private def filterFiles(path: String, pattern: String, matcher: (String, String) => Boolean) = {
val files = (new java.io.File(path)) listFiles
for(file <- files if matcher(file.getName, pattern)) yield file
}
And the IDE gives me errors on both lines of the body. The error of the first line says:
ambiguous reference to overloaded definition, both method listFiles in class File of type (x$1: java.io.FileFilter)Array[java.io.File] and method listFiles in class File of type
(x$1: java.io.FilenameFilter)Array[java.io.File] match argument types (Null)
the error on the second line says:
illegal start of simple expression
and all the three calls to the printArray() in the test() method now also tell this:
type mismatch; found : Unit required: Array[?]
What does it all mean? Scala is not supposed to behave like Python when code alignment can ruin the code flow... so how come that removing the blank line between the first and the second line of the body of the filterFiles() method puts up such a serious error? Is it a bug somewhere or does it follow directly from the rules of Scala? Note: if I add ; between the line, it sorts everything out. Is it just semicolon inference bug?
When object's method can none or single argument you can call it like
val files = object method arg
or, in your snippet
val files = object method
arg
In your code compiler wants to call listfiles with an for expression as an agument which returns Array[File]. And complains that listFiles hasn't implementation with this type of argument. Empty line prevents treating for expression as a parameter for listFiles function
Looks like semicolon inference problem as you suggest, I guess the compiler expects method arguments if you leave parenthesis out. Instead of semicolon, you can add parenthesis after listFiles:
val files = (new java.io.File(path)) listFiles ()