Dean Hiller
Dean Hiller

Reputation: 20182

What is the difference between different function creations

This question is heavily related to my other question (and may lead to me solving that one) but is definetely different.

how to allow passing in a => AnyRef function and call that function

I have been playing with different function creations and I am frankly having trouble creating an anonymous function of type => AnyRef and => String. I can create a function of type () => AnyRef and () => String I think.

Example 1 I have the following code

def debugLazyTest2(msg: => String) : Unit = {
  System.out.println(msg)
}

//and client code
  val function: () => String = () => {
    executed = true
    "asdf"+executed+" hi there"
  }
  log2.debugLazyTest2(function)

but the compile error says found: () => String which makes sense but then says "required: String" instead of "required: => String"

What is going on here?

Example 2 to get even more bizarre, I have this code which compiles while above did not compile

def debugLazyTest(msg: => AnyRef) : Unit = {
  System.out.println(msg.toString)
}

//and client code which compiles!!!!
  val function: () => AnyRef = () => {
    executed = true
    "asdf"+executed+" hi there"
  }
  log2.debugLazyTest(function)

This code compiles though it doesn't work the way I would like as the library can't seem to invoke the function before toString is called (that is in my other thread and is a separate question).

Any ideas as to what is going on here?

thanks, Dean

Upvotes: 0

Views: 104

Answers (2)

Patrick Prémont
Patrick Prémont

Reputation: 938

If you wrote this it would work:

log2.debugLazyTest2(function())

msg is a by-name parameter, not a function. You have to pass in an expression of type String (or AnyRef in the second example)

The second example compiles because the () => AnyRef you pass in is actually also an AnyRef, since a function is an AnyRef. But then it is the function itself that is printed, not the result of executing it.

Upvotes: 3

Sean Vieira
Sean Vieira

Reputation: 159855

Consider the following code:

scala> def test(x: String) = debugLazyTest2(x)
test: (x: String)Unit

If we then run (in Scala 2.11.2):

:javap test

And trim a bit of the generated output, we see the following:

  public void test(java.lang.String);
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=2, args_size=2
         0: getstatic     #19                 // Field .MODULE$:L;
         3: new           #21                 // class $anonfun$test$1
         6: dup
         7: aload_1
         8: invokespecial #23                 // Method $anonfun$test$1."<init>":(Ljava/lang/String;)V
        11: invokevirtual #27                 // Method .debugLazyTest2:(Lscala/Function0;)V
        14: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      15     0  this   L;
               0      15     1     x   Ljava/lang/String;
      LineNumberTable:
        line 8: 0

And then we consider the signature for debugLazyTest2:

 public void debugLazyTest2(scala.Function0<java.lang.String>);

The key line is:

         3: new           #21                 // class $anonfun$test$1

If I am reading the code correctly, we are instantiating a new instance of the class $anonfun$test$1 - and passing that new anonymous Function0[String] to debugLazyTest2. This makes our test method equivalent to the following:

def test(x: String) = debugLazyTest2(new Function0[String] {
    def apply(): String = x
})

When we consider passing in an instance of Function0[String] to debugLazyTest2 making the same transformation, we get:

debugLazyTest2(function)

which becomes:

debugLazyTest2(new Function0[String] {
    def apply(): Function0[String] = function
})

which, of course, does not compile, because apply(): Function0[String] does not match the required type apply(): String (hence the error message).

Actually invoking the function instead of returning it works:

debugLazyTest2(function())

becomes:

debugLazyTest2(new Function0[String] {
    def apply(): String = function()
})

Upvotes: 3

Related Questions