In scala, there is some call-by-name parameters:
def hello(who: => String) = println("hello, " + who)
What's the type of the parameter who
?
It shows the function on scala REPL as:
hello: (who: => String)Unit
Is the type still => String
? Is there any name for it? Or some documentation to describe the type?
(When reading the spec of §3.3.1 (MethodTypes))
Method type is the type of a method, say I defined a method hello
:
def hello: String = "abc"
The type of the it can be written as: => String
, right? Although you can see the REPL response is:
scala> def hello:String = "abc"
hello: String
If I define a method which has parameters:
def goodname(name: String): String = name + "!"
What's the type of the method? It should be similar to String => String
, but not. Because it's a method type, and String => String
is a function type.
(When reading the spec of §3.3.1 (MethodTypes))
I can understand this as:
def goodname(name: String): String = name + "!"
def print(f: String => String) = println(f("abc"))
print(goodname)
When I call print(goodname)
, the type of goodname
will be converted to the function type String => String
, right?
But for paramless method:
def hello: String = "abc"
What function type can it be converted? I tried:
def print(f: () => String) = println(f())
But this can't be compiled:
print(hello)
The error is:
error: type mismatch; found : String required: () => String
Could you give me an example that works?
(When reading the spec of §6.26.2 (MethodConversions))
This Evaluation conversion is only happened when the type is not applied to argument. So, for code:
def myname:String = "abc"
def print(name: => String) = println(name)
print(myname)
My question is, when I call print(myname)
, is there conversion(I mean Evaluation conversion
) happened? I guess, since the type of myname
is just => String
, so it can be passed to print
directly.
If the print
method has changed:
def myname:String = "abc"
def print(name: String) = println(name)
print(myname)
Here the Evaluation conversion
is definitely happened, right?(From => String
to String
)
Quoting from §4.6.1 of the spec:
The type of such a parameter is then the parameterless method type
=> T
.
So the type of a call-by-name param is (approximately) () => T
(or Function0[T]
if you prefer). If you :javap
a method that accepts a call-by-name parameter you will see that the compiled code accepts a param of the type scala.Function0<java.lang.Object>
.
The translation of:
def callByName[T](f: => T) = f
callByName { /* magic */
1 + 1
/* ends here */ }
is effectively:
def callByName[T](f: Function0[T]) = f.apply()
callByName(new Function0[Int] {
def apply() = { /* magic */
1 + 1
/* ends here */ }
})
You may be tempted to try passing a () => T
to your method. Try callByName(() => 12)
; why does it not compile? (Hint, consider the expansion at the call site). (Hover on the following blank to see the answer):
The reason
callByName(() => 12)
does not compile is because the expansion is treated as: callByName(new Function0[() => Int] { def apply() = () => 12 }) That is, rather than passing in aFunction0
which returns anInt
you are passing in aFunction0
which returns aFunction0
which returns anInt
.
=> T
actually is=> T
is actually a method type, not an object. So everything that goes before is an approximation of what the compiler does and can change at any time. Quoting from §3.3:
The types explained in the following do not denote sets of values, nor do they appear explicitly in programs. They are introduced in this report as the internal types of defined identifiers.
So what are method types? Quoting from §3.3.1 (MethodTypes):
A special case are types of methods without any parameters. They are written here
=> T
. Parameterless methods name expressions that are re-evaluated each time the parameterless method name is referenced.Method types do not exist as types of values. If a method name is used as a value, its type is implicitly converted to a corresponding function type (§6.26).
And §6.26.3 (MethodConversions) states:
The following four implicit conversions can be applied to methods which are not applied to some argument list.
Evaluation. A parameterless method
m
of type=> T
is always converted to typeT
by evaluating the expression to whichm
is bound.
So the proper translation of the type => T
is always:
def random$name$here: T
Here's an example class to play around with:
class TestParamless {
def paramless: Int = 1
def callByName(f: => Int) = f
def example: Int = callByName(paramless)
}
Try new TestParamless().example
and also, :javap TestParamless
(in the scala REPL).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With