Why in Scala function defined without empty parentheses doesn't behave like function? - scala

Consider the following 2 objects
object TestObj1 {
def testMethod = "Some text"
}
object TestObj2 {
def testMethod() = "Some text"
}
and if I call those methods directly, they do what I expect
scala> TestObj1.testMethod
res1: String = Some text
scala> TestObj2.testMethod
res2: String = Some text
But now if we define following function
def functionTakingFunction(callback: () => String) {
println("Call returns: " + callback())
}
and try to call it, the method defined without () is not accepted.
scala> functionTakingFunction(TestObj1.testMethod)
<console>:10: error: type mismatch;
found : String
required: () => String
functionTakingFunction(TestObj1.testMethod)
^
scala> functionTakingFunction(TestObj2.testMethod)
Call returns: Some text
I also noticed that you can't call the TestObj1.testMethod using parentheses, since it already is a String. But what is causing this behavior?

You are not passing the method, you're invoking it and then passing its result into the call.
If you want to pass the method, you first have to convert it into a function, and pass that:
functionTakingFunction(TestObj1.testMethod _)
Here the testMethod is converted into a partially applied function (said to be "tied").
The reason you have to do that is because TestObj1.testMethod does not evaluate to function0 (which is what need to be passed to functionTakingFunction), but to a String because of the way it is declared (without parentheses).
It works on TestObj2 because the testMethod is defined with parentheses and thus just typing TestObj2.testMethod does not invoke it.

functionTakingFunction(TestObj1.testFunction) is called as functionTakingFunction("Some text") - it is evaluated rather than passed

Here, you are not passing the function. What you are trying to do is evaluate TestObj1.testFunction and then pass that result to functionTakingFunction
But if you see the definition of functionTakingFunction, it says clearly
def functionTakingFunction(callback: () => String)
means this function expects a function with Return Type as Unit. But TestObj1.testFunction is having no return type.
The difference between Unit Return Type and No Return Type is:
No Return Type means this method will not return anything
Unit Return Type means this method will return something which is having no meaningful value.
Hope it helps you now. Happy coding and enjoy Scala.

Related

Scala - Function's implicit return type

I am new to scala, and got a little doubt about function definition & default return type.
Here is a function definition:
def wol(s: String) = s.length.toString.length
The prompt says it's:
wol: (s: String)Int
But, the code didn't specify return type explicitly, shouldn't it default to Unit, which means void in Java.
So, what is the rules for default return type of a Scala function?
The return type in a function is actually the return type of the last expression that occurs in the function. In this case it's an Int, because #length returns an Int.
This is the work done by the compiler when it tries to infer the type. If you don't specify a type, it automatically gets inferred, but it's not necessarily Unit. You could force it to be that be stating it:
def wol(s: String): Unit = s.length.toString.length
EDIT [syntactic sugar sample]
I just remembered something that might be connected to your previous beliefs. When you define a method without specifying its return type and without putting the = sign, the compiler will force the return type to be Unit.
def wol(s: String) {
s.length.toString.length
}
val x = wol("") // x has type Unit!
IntelliJ actually warns you and gives the hint Useless expression. Behind the scene, the #wol function here is converted into something like:
// This is actually the same as the first function
def wol(s: String): Unit = { s.length.toString.length }
Anyway, as a best practice try to avoid using this syntax and always opt for putting that = sign. Furthermore if you define public methods try to always specify the return type.
Hope that helps :)

Trying to skip implicit parameter list

I'd like to call a function returned by a function with an implicit parameter, simply and elegantly. This doesn't work:
def resolveA(implicit a: A): String => String = { prefix =>
s"$prefix a=$a"
}
case class A(n: Int)
implicit val a = A(1)
println(resolveA("-->")) // won't compile
I've figured out what's going on: Scala sees the ("-->") and thinks it's an attempt to explicitly fill in the implicit parameter list. I want to pass that as the prefix argument, but Scala sees it as the a argument.
I've tried some alternatives, like putting an empty parameter list () before the implicit one, but so far I've always been stopped by the fact that Scala thinks the argument to the returned function is an attempt to fill in the implicit parameter list of resolveA.
What's a nice way to do what I'm trying to do here, even if it's not as nice as the syntax I tried above?
Another option would be to use the apply method of the String => String function returned by resolveA. This way the compiler won't confuse the parameter lists, and is a little shorter than writing implicltly[A].
scala> resolveA[A].apply("-->")
res3: String = --> a=A(1)

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".

Right associative functions with two parameter list

I was looking at the FoldLeft and FoldRight methods and the operator version of the method was extremely peculiar which was something like this (0 /: List.range(1,10))(+).
For right associative functions with two parameter lists one would expect the syntax to be something like this((param1)(param2) op HostClass).
But here in this case it is of the syntax (param1 op HostClass)(param2). This causes ambiguity with another case where a right associative function returns another function that takes a single parameter.
Because of this ambiguity the class compiles but fails when the function call is made as shown below.
class Test() {
val func1:(String => String) = { (in) => in * 2 }
def `test:`(x:String) = { println(x); func1 }
def `test:`(x:String)(y:String) = { x+" "+y }
}
val test = new Test
(("Foo") `test:` test)("hello")
<console>:10: error: ambiguous reference to overloaded definition,
both method test: in class Test of type (x: String)(y: String)String
and method test: in class Test of type (x: String)String => String
match argument types (String)
(("Foo") `test:` test)("hello")
so my questions are
Is this an expected behaviour or is it a bug?
Why the two parameter list right associative function call has been designed the way it is, instead of what I think to be more intuitive syntax of ((param1)(param2) op HostClass)?
Is there a workaround to call either of the overloaded test: function without ambiguity.
The Scala's Type System considers only the first parameter list of the function for type inference. Hence to uniquely identify one of the overloaded method in a class or object the first parameter list of the method has to be distinct for each of the overloaded definition. This can be demonstrated by the following example.
object Test {
def test(x:String)(y:Int) = { x+" "+y.toString() }
def test(x:String)(y:String) = { x+" "+y }
}
Test.test("Hello")(1)
<console>:9: error: ambiguous reference to overloaded definition,
both method test in object Test of type (x: String)(y: String)String
and method test in object Test of type (x: String)(y: Int)String
match argument types (String)
Test.test("Hello")(1)
Does it really fail at runtime? When I tested it, the class compiles, but the call of the method test: does not.
I think that the problem is not with the operator syntax, but with the fact that you have two overloaded functions, one with just one and the other with two parameter lists.
You will get the same error with the dot-notation:
test.`test:`("Foo")("hello")
If you rename the one-param list function, the ambiguity will be gone and
(("Foo") `test:` test)("hello")
will compile.

Pass function argument as code block

I am new to Scala. I have been searching but there is no easy "search string" for the seemingly easy question I have.
def foo( f: (String) => String ){println(f("123"))}
foo{_+"abc"} //works
def bar( f :() => String ){println(f())}
bar{"xyz"} // why does this not work?
def baz( f: => String ){println(f)}
baz{"xyz"} //works
Why does the second (bar) not work?
Second baz works because it's not a function literal, but a call-by-name parameter. Basically what it does is delaying the moment of argument computation until it's needed in the program. You can also read about this in this question.
As for bar you just need to pass a function like bar{() => "xyz"}
bar accepts a function that takes no arguments and returns String. You gave it just a String. To make it work:
bar{() => "xyz"}
This case is special to parameterless functions/blocks.
object Fs2 {
def f0=1
def f0_1()=1
}
object Main extends App {
println(Fs2.f0)
//println(Fs2.f0()) wont compile
println(Fs2.f0_1)
println(Fs2.f0_1())
}
Unit "()" is optional for f0_1. Adding it to f0 will cause an error. f0 does not accept any parameter. Unit itself is a parameter declaring there is no parameter. Fs2.f0 corresponds to baz, Fs2.f0() corresponds to bar.