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.
Related
I am learning Scala and running below code .I knew functions, that do not return anything is procedures in Scala but when running below code why extra () is coming in output. Here in procedure i am just printing the value of 'value'.
Can someone explain about this.
class Sample{
private var value = 1
def test() {value += 2; println(value)}
def test2() = value
}
object Main2 extends App {
val my_counter = new Sample()
println(my_counter.test())
println(my_counter.test2())
}
3
()
3
The so-called "procedure syntax" is just "syntactic sugar" for a method that returns Unit (what you would call void in Java).
def sayHello(toWhom: String) {
println(s"hello $toWhom")
}
Is semantically equivalent (and gets actually translated) to:
def sayHello(toWhom: String): Unit = {
println(s"hello $toWhom")
}
Notice the explicit type and the equal sign right after the method signature.
The type Unit has a single value which is written () (and read unit, just like it's type). That's what you see: the method test prints value and then produces () of type Unit, which you then move on to print on the screen itself.
As noted in a comment, the "procedure syntax" is deprecated and will be removed in Scala 3.
Procedure syntax compiles to a method that returns unit.
calling toString on Unit produces "()"
You are printing out the result of test (which is Unit) so you see its string representation, () in the output.
In Scala (Play Framework), I can't understand the type signatures even though I read through all the symbols in here.
For example:
/* matches if a == b */
def equalTo[T](t: => T): BeEqualTo
class BeEqualTo(t: => Any)
extends BeTypedEqualTo[Any]
What on earth do these type signatures even mean?
For example, what exactly is "a" and "b" in the documentation? All I see is "t". Is equalTo a function that takes in a function which returns a value of generic type T?
Another example...
Say I have this line...
status(home).must(equalTo(OK))
According to the IDE, OK is a pattern or symbol of type Int. So OK is an Int? You can monkey-patch an int to give it a function like "must", but how can an Int go inside of "equalTo", a function that takes in a function?
Now some of the type signatures make sense. For example...
def status(of: Future[Result])(implicit timeout: Timeout): Int
^ This is a curried function that takes in a future that returns something of type Result and that sucks in an implicit parameter of type Timeout from somewhere (Scala magic) and returns an Int. "home" is of type "Future[Result]", so it fits inside "status".
But other stuff...
contentType(home).must(beSome.which(_ == "text/html"))
^ My IDE says that beSome is of type
def beSome[T](check: ValueCheck[T]): SomeCheckedMatcher[T]
^ So "beSome" is a function. If that is the case, then how on earth can I appeand ".which()", another function, to it as if it were an object?
Another example...
def which[R : AsResult](f: (U) => R): OptionLikeCheckedMatcher[F, Nothing, U]
^ How on earth do you read these type signatures? "which" takes in "f: (U)", or a variable which we call "f" of type "(U)"? Why the unnecessary parenthesis around the "(U)"? Can't you just say "f: U" and make U be a String if R is a String?
"must" is like this...
def must(m: => Matcher[T]): MatchResult[T]
^ So "must" takes in a function that returns a Matcher. But "which" is passing in an OptionLikeCheckedMatcher. "m: => Matcher[T]" is a function that takes in an "m" and returns a "Matcher[T]". How is that the same as an object of type OptionLikeCheckedMatcher?
Can someone provide a definitive guide as to how to read Scala type signatures?
I think you're getting a little confused with the distinction between a function-valued parameter and a call-by-name parameter. They are similar but not quite the same. In the first example you posted, def equalTo[T](t: => T): BeEqualTo, the : => notation means that the parameter is not evaluated immediately (as it would be if it were declared with just a colon), but every time it is used in an expression. This link might clarify things a bit for you: https://tpolecat.github.io/2014/06/26/call-by-name.html
In another example you posted, def which[R: AsResult](f: (U) => R): OptionCheckedLikeMatcher[F, Nothing, U] takes in a function parameter called f, which accepts a U as its argument and returns a T. The brackets around the U are indeed unnecessary, but they would have been necessary if (for example) f were a function taking 2 parameters of type U - we would then have written it as f: (U, U) => R. The return value of which will be an OptionCheckedMatcher. Assuming that this is a subtype of Matcher (which seems sensible), this is the value which is passed to must.
I've written a simple code in Scala with implicit conversion of Function1 to some case class.
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
def someFunction(i:Int):String = "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction))
}
But it doesn't work. Compiler doesn't want to pass someFunction as an argument to abc. I can guess its reasons but don't know exactly why it doesn't work.
When you use a method name as you have, the compiler has to pick how to convert the method type to a value. If the expected type is a function, then it eta-expands; otherwise it supplies empty parens to invoke the method. That is described here in the spec.
But it wasn't always that way. Ten years ago, you would have got your function value just by using the method name.
The new online spec omits the "Change Log" appendix, so for the record, here is the moment when someone got frustrated with parens and introduced the current rules. (See Scala Reference 2.9, page 181.)
This has not eliminated all irksome anomalies.
Conversions
The rules for implicit conversions of methods to functions (§6.26) have been tightened. Previously, a parameterized method used as a value was always implicitly converted to a function. This could lead to unexpected results when method arguments were forgotten. Consider for instance the statement below:
show(x.toString)
where show is defined as follows:
def show(x: String) = Console.println(x)
Most likely, the programmer forgot to supply an empty argument list () to toString. The previous Scala version would treat this code as a partially applied method, and expand it to:
show(() => x.toString())
As a result, the address of a closure would be printed instead of the value of s. Scala version 2.0 will apply a conversion from partially applied method to function value only if the expected type of the expression is indeed a function type. For instance, the conversion would not be applied in the code above because the expected type of show’s parameter is String, not a function type. The new convention disallows some previously legal code. Example:
def sum(f: int => double)(a: int, b: int): double =
if (a > b) 0 else f(a) + sum(f)(a + 1, b)
val sumInts = sum(x => x) // error: missing arguments
The partial application of sum in the last line of the code above will not be converted to a function type. Instead, the compiler will produce an error message which states that arguments for method sum are missing. The problem can be fixed by providing an expected type for the partial application, for instance by annotating the definition of sumInts with its type:
val sumInts: (int, int) => double = sum(x => x) // OK
On the other hand, Scala version 2.0 now automatically applies methods with empty parameter lists to () argument lists when necessary. For instance, the show expression above will now be expanded to
show(x.toString())
Your someFunction appears as a method here.
You could try either
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
val someFunction = (i:Int) => "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction))
}
or
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
def someFunction(i:Int): String = "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction(_: Int)))
}
By the way: implicitly casting such common functions to something else can quickly lead to problems. Are you absolutely sure that you need this? Wouldn't it be easier to overload abc?
You should use eta-expansion
println(abc(someFunction _))
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.
def func(arg: String => Int): Unit = {
// body of function
}
I mean this fragment:
String => Int
Short answer
Its a function that receives a String and returns a Int
Long answer
In Scala, functions are first class citizens. That means you can store them in variables or (like in this case) pass them around as arguments.
This is how a function literal looks like
() => Unit
This is a function that receives no arguments and returns Unit (java's equivalent to void).
This would be a function that receives a String as a parameter and returns an Int:
(String) => Int
Also, scala let's you drop the parenthesis as a form of syntactic sugar, like in your example. The preceding arg: is just the name of the argument.
Inside func you would call the function received (arg) like this:
val result = arg("Some String") // this returns a Int
As mentioned in Advantages of Scala’s Type System, it is a Functional type.
The article Scala for Java Refugees Part 6: Getting Over Java describes this syntax in its section "Higher-Order Functions".
def itrate(array:Array[String], fun:(String)=>Unit) = {
for (i <- 0 to (array.length - 1)) { // anti-idiom array iteration
fun(array(i))
}
}
val a = Array("Daniel", "Chris", "Joseph", "Renee")
iterate(a, (s:String) => println(s))
See? The syntax is so natural you almost miss it.
Starting at the top, we look at the type of the fun parameter and we see the (type1, …)=>returnType syntax which indicates a functional type.
In this case, fun will be a functional which takes a single parameter of type String and returns Unit (effectively void, so anything at all).
Two lines down in the function, we see the syntax for actually invoking the functional. fun is treated just as if it were a method available within the scope, the call syntax is identical.
Veterans of the C/C++ dark-ages will recognize this syntax as being reminiscent of how function pointers were handled back-in-the-day.
The difference is, no memory leaks to worry about, and no over-verbosity introduced by too many star symbols.
In your case: def func(arg: String => Int): Unit, arg would be a function taking a String and returning an Int.
You might also see it written (perhaps by a decompiler) as
def func(arg: Function1[String, Int]): Unit = {
// body of function
}
They are precisely equivalent.