tags:

views:

132

answers:

3

This doesn't compile with Scala 2.7.7.final or 2.8.0.final for me:

new FileInputStream("test.txt") getChannel transferTo(
    0, Long.MaxValue, new FileOutputStream("test-copy.txt") getChannel)

This does compile with Scala 2.7.7.final and 2.8.0.final for me:

new FileInputStream("test.txt") getChannel() transferTo(
    0, Long.MaxValue, new FileOutputStream("test-copy.txt") getChannel)

Why is it that I need to do getChannel() instead of just getChannel here?

+1  A: 

I believe because it's not clear to the compiler how to divide the tokens up. Is it new FileInputStream("test.txt")(getChannel, transferTo(...))? new (FileInputStream("test.txt"), getChannel, transferTo(...))? (new FileInputStream("test.txt")).getChannel(transferTo(...))? The compiler doesn't have enough information to know that transferTo is a property of the object returned by getChannel.

For maximum clarity you'd have something like:

(new FileInputStream("test.txt")).getChannel().transferTo(
  (new FileOutputStream("test-copy.txt")).getChannel(), 0, Long.MaxValue)
pr1001
+2  A: 

The reason is really simple. If you are using spaces instead of .'s to chain method calls then:

 a b c d     //is parsed as a call to
 (a.b(c))(d)

In your case the last two parameters are being called like (because d is more than one parameter, d, e and f say):

a b c(d, e, f)    //is parsed as a call to
a.b(c(d, e, f))

i.e. the same as the first case. However, you want the call to be:

(a b).c(d, e, f)

Which is not the same!

  • a = new FileInputStream("test.txt")
  • b = getChannel
  • c = transferTo
  • d = new FileOutputStream("test-copy.txt") getChannel
  • e = 0
  • f = Long.MaxValue

This has not changed between 2.7 and 2.8 as far as I'm aware!

oxbow_lakes
Thank you oxbox_lakes, the 2.7/2.8 point is accurate. I retested the two cases in 2.7.7.final and 2.8.0.final and found the behavior to be the same. I have amended my question to reflect that and limit confusion.
Alain O'Dea
I'm pretty sure the parsing is `a.b(c(d, e, f))` -- ie, `apply` inference on objects (parameters) before operator resolution.
Daniel
Apols for the mistake Daniel - fixed now
oxbow_lakes
+4  A: 

The general rule is that the compiler interprets strings like

new FileInputStream("test.txt") getChannel transferTo(...)

as

object method parameter method parameter method parameter

so in your case, that means

new FileInputStream("test.txt")    // object
getChannel                         // method
transferTo(...)                    // parameter

so the compiler tries to call transferTo as a free function so it can pass its result as a parameter to getChannel. When you add the parentheses, you get

new FileInputStream("test.txt") getChannel() transferTo(...)

new FileInputStream("test.txt")    // object
getChannel                         // method
()                                 // parameter (empty parameter list)
transferTo                         // method
(...)                              // parameter
Ken Bloom