Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the type of `=> String` in scala?

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?

Further questions raised by answer

Question 1

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

Question 2

(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?

Question 3

(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)

like image 985
Freewind Avatar asked Mar 19 '23 16:03

Freewind


1 Answers

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

An example of the approximation

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 */ }
})

Doubts surrounding the approximation

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 a Function0 which returns an Int you are passing in a Function0 which returns a Function0 which returns an Int.

What => 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 type T by evaluating the expression to which m is bound.

So the proper translation of the type => T is always:

def random$name$here: T

Example

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

like image 114
Sean Vieira Avatar answered Mar 27 '23 17:03

Sean Vieira