views:

172

answers:

2

When writing the following code in scala

var m = Map((0,1) -> "a")
m += ((0,2), "b") // compilation error

I'm getting the error

type mismatch;
 found   : Int(0)
 required: (Int, Int)

However the changing the syntax of the tuple from (X,Y) to (X -> Y) works

var m = Map((0,1) -> 'a)
m += ((0,2) -> 'b) // compiles file

Even though

((0,1).getClass == (0 -> 1).getClass) // is true
(0,1).isInstanceOf[Tuple2[_,_]] && (0 -> 1).isInstanceOf[Tuple2[_,_]] // both true

Why is that? What does scala think my nested tuple is?

+10  A: 

The reason is pretty simple (I think) and has to do with the fact that (on the Map trait):

m += (a -> b)

is shorthand for:

m = m.+(t2) //where t2 is of type Tuple2[A,B]

Obviously if you use a comma in the first example, Scala will interpret this as being a call to the method:

m = m.+(a, b)

This method does not exist on the Map trait. Method invocation rules mean that a -> b gets evaluated first (to the Tuple2) and hence the correct method is called. Note: Using an extra pair of parentheses works just fine:

m += ( (a,b) ) //works just fine but less readable
oxbow_lakes
I was actually pretty sure that Obj Op Pred is equivalent to Pred.Op((Pred)) already. Is there a use (in the standard library, or Lift) for calling a function with two arguments as an operator? (An example which makes sense of course, you can always do "array update (x,y)" but it just looks strange.
Elazar Leibovich
I agree with you Elazar. I think that the compiler should have a bit more sense here
oxbow_lakes
A: 

Oxbow is correct. You can use another parenthesis to disambiguate, though:

m += (((0,2), "b"))
Daniel
I believe I pointed out that the extra parentheses solved the issue
oxbow_lakes