I thought () was the only instance of Unit in Scala.
When I try to set a function to anonymous func variable, this works:
def some(a:Unit):Unit = {
println("Enigma")
}
val func:Unit => Unit = some
func()
But this does not:
def some():Unit = {
println("Enigma")
}
val func:Unit => Unit = some
An empty parameter list as in your second example is not the same as Unit which is a value that represents something like null. () doesn't always mean Unit in every context,
specifically the instance where your dealing with an argument list.
This is because your second example is a method without any arguments.
Take a look at the types that results:
some: (a: Unit)Unit
some: ()Unit
which would be written in a type assignment as
Unit => Unit
() => Unit
In the second case, the parens are not acting as Unit, but instead are merely the string representation of an argumentless function. () is only symbolic as Unit in the context of a method. In a type signature you use Unit, because () is expected to be a function with no arguments
def some(): Unit
The () here is not the instance of Unit, just no argument.
The normal usage of () is
def some(): Unit = ()
But if you enter Some() in Scala interpreter, you will get
scala> Some()
res0: Some[Unit] = Some(())
Well, it's strange, seems that Scala rewrites Some() to Some(()). Anyway, I will not write code like this, it makes things hard to understand.
Related
I'm getting some unexpected behavior when using a call by name function in Scala. Can anybody explain the difference here?
class Button( act: => Unit) {def fire = act}
def foo() {println("foo got called")}
val x= new Button(foo)
x.fire
val y= new Button(foo _)
y.fire
x.fire causes foo to be called.
y.fire does not.
Why?
What function is being passed to y?
Thanks!
You should probably define your class a bit differently.
class Button( act: () => Unit) {def fire = act()}
Notice you are now taking in a Function0[Unit] instead of a call-by-name Unit value. This new definition has better typesaftey since it requires a function, while yours will accept any value, and will do nothing unless there are side effect required to evaluate the value passed in. We also now call the function passed in for its side effects instead of just returning it.
The problem with Unit is that when a unit is required any value can be provided which will be automatically discarded for a Unit. For example, with your code new Button(5) is valid, as is the code val x: Unit = 5.
The reason the first code class Button( act: => Unit) {def fire = act} "works", is you call the method foo, and pass the result into the Button constructor. Since it's a by-name parameter foo doesn't actually run until it's used. When you then use the Unit value passed into the class, the expression needs to be evaluated so foo is fun.
You second example is different however, adding the underscore (foo _) now means that you are passing in the method itself as a function, instead of calling the method and passing in the result as in your first example. It's perfectly fine to pass a function in to the constructor even thought the type now is not Unit since as discussed earlier any value can be discarded and replaced by Unit. When you evaluate the Unit value, there are no side effects this time since you don't run the method to get the unit, just create a function which is the discarded without being run. def fire = act
When you change the type to be a function.
class Button( act: () => Unit) {def fire = act()}
now only a () => Unit is a valid argument instead of anything, and the fire method runs that function.
Here is a possible explanation!
scala> foo _
res14: () => Unit = <function0>
scala> foo
foo got called
scala>
Can you see why now?
Because Button takes a (delayed) Unit as a constructor argument, you'd think that the call to new Button(foo _) wouldn't be allowed because () => Unit is not the same thing as =>Unit. But it turns out that => Unit is, essentially, the universal accepter.
new Button()
new Button(99)
new Button("str")
You'll get warnings, but these all compile and run, and you can invoke the fire method on them (but it won't do anything).
Referring to following question in SO, what is the usefulness of passing Unit to a function instead of () or vice versa?
Functions without arguments, with unit as argument in scala
From what I can tell you would like to know what is the difference between these two method definitions, and why one would use Unit over () in the function parameter.
def func1(f:Unit=>String) = {
println(f)
}
def func2(f:()=>String) = {
println(f)
}
the difference can be highlighted by looking at the output of this code:
func1(Unit => "hello")
func2(() => "hello" )
you may be surprised to see this output:
<function1>
<function0>
Unit=>String is actually a function with 1 parameter. While ()=>String is a function with 0 parameters.
In Scala () could mean two things
it could be used for Unit e.g. val x:Unit = ()
it can be use to represent no parameters.
In func2, it is a function with no parameters.
"Unit" in func1 is actually the abstract class in the scala package (of which there is only one value "Unit" or "()"). So when the function Unit => String was defined, what we defined was a function that takes a parameter of type Unit as a parameter, and returns a value. Not a Function that takes no parameters.
A final tweak to the code to highlight the difference:
def func1(f:Unit=>String) = {
println(f(Unit))
}
def func2(f:()=>String) = {
println(f())
//println(f(Unit)) - does not compile
}
func1(Unit => "hello")
func2(() => "hello" )
Will output hello twice.
I'd suggest that func2 or () is generally what people want, and not func1 or "Unit"
I've found a Scala code snippet which declares a method <init> and puts () right below the invocation.
I have a question about line number 5. What does () mean here?
(() => {
final class $anon extends MutableProjection {
def <init>() = {
super.<init>();
()
};
...
};
new $anon()
})
Here is a code with full example.
Every Scala function has a return type. By convention (and highly encouraged by some language features), functions that don't need to return anything have a return type called Unit, which has a singleton value written as ().
The last expression in a function body is its return value. That author made this be () to cause the compiler to infer that the return type should be Unit. But it would have been more clear to just do that with a type annotation. If a function's return type is Unit, Scala will implicitly return () from the function no matter what the last statement in the body is. So this
def <init>() = {
super.<init>()
()
}
could be written equivalently as
def <init>(): Unit = super.<init>()
() can meean a few things, depending on context.
As a value, it is an empty tuple, or the singleton type. It's type is Unit.
It can denote a function or method that takes no parameters, such as:
def foo() = "Hello world"
Note that when writing an anonymous function, the () is by itself but still means a function with no parameters.
val x = () => 2
The type of x is () => Int, a function taking no parameters and returning an int.
As a source of infinite confusion, you can get examples like this:
val y = () => ()
The type of y here is () => Unit, a function of no parameters returning Unit, not Unit => Unit, which would be writen as val z = (x:Unit) => (), and called like z(())
The unit vs empty parameter distinction has been awkward for me in the past so hopefully that demystifies some of it.
Why does this compile
scala> import scala.concurrent.Future
import scala.concurrent.Future
scala> val f: Unit = Future.successful(())
f: Unit = ()
I expected the compiler to complain about the assignment.
This is called "Value Discarding". Citing the scala specification (6.26.1):
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; () }.
In other words, any value, whatever its type, is implicitly converted to Unit, effectively discarding it.
It you want to be warned about such discarding (which can in some cases hide a bug), you can pass the -Ywarn-value-discard option to the compiler. You'll then have to explicitly return () every time you call a method only for its side effect, but that method does return a non-Unit value.
The compiler is fine since applying f will only execute the call
val f: Unit = Future.successful(())
and the return value will go into the nirvana.
Basically this is the same as:
val f: Unit = {
Future.successful(())
()
}
If the compiler don't find the Unit it expects in the last value of the method it will put it there.
I came across a situation recently where I needed to create a function to call a parameterless constructor. The following code demonstrates
class NoNumber() {}
val create : Unit => NoNumber = Unit => new NoNumber()
val nn = create()
This code compiles and creates a new instance of NoNumber and assigns it to nn as expected. However, there are a couple of things I wasn't expecting.
my first attempt (which doesn't compile), was as follows
val create : Unit => NoNumber = () => new NoNumber()
Why is it that Unit works and () does not work in the above example? I was under the impression that () was the one and only instance of Unit and as such the () seems to make the most sense.
Secondly I see the following warning when compiling the code
Warning:(3, 22) Adaptation of argument list by inserting () has been
deprecated: this is unlikely to be what you want. signature:
Function1.apply(v1: T1): R given arguments: after
adaptation: Function1((): Unit) lazy val nn = create()
What does this mean and how should the code be changed to remove the warning?
Thanks
Unit => A and () => A are not the same thing.
Unit => A is syntactic sugar for Function1[Unit, A], a function with a single argument of Unit that returns A. You're confusing the type Unit with the value () that has type Unit. i.e., you cannot say:
scala> val a: () = ()
<console>:1: error: '=>' expected but '=' found.
val a: () = ()
^
() => A is syntactic sugar for Function0[A], a parameter-less function that returns A. They are similar, but not quite the same.
As for the warning with this:
val create : Unit => NoNumber = Unit => new NoNumber()
If you were to have val nn = create, then nn would actually be a function, Unit => NoNumber. When you have:
val nn = create()
You are actually are doing:
val nn = create.apply(())
Confusing, yes? Hence, the deprecation warning. The former is simply passing () to a Function1[Unit, NoNumber], but it looks awfully like a Function0. What you probably want is:
val create : () => NoNumber = () => new NoNumber()