2

I am getting a taste of Scala through the artima "Programming in Scala" book.

While presenting the Map traits, the authors go to some lengths to describe the -> syntax as a method that can be applied to any type to get a tuple.

And indeed:

scala> (2->"two")
res1: (Int, String) = (2,two)

scala> (2,"two")
res2: (Int, String) = (2,two)

scala> (2->"two") == (2, "two")
res3: Boolean = true

But those are not equivalent:

scala> Map(1->"one") + (2->"two")
res4: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two)

scala> Map(1->"one") + (2, "two")
<console>:8: error: type mismatch; 
found   : Int(2)
required: (Int, ?)
             Map(1->"one") + (2, "two")

Why is this so, since my first tests seem to show that both "pair" syntaxes build a tuple?

Regards.

5
  • 3
    In fact they are equivalent: (2->"two") is analog to ((2, "two")) and Map(1 -> "one") + ((2, "two")) works just fine. Map(1 -> "one") + 2 -> "two" wont work with the same error as Map(1->"one") + (2, "two") Commented Jun 25, 2013 at 21:07
  • Could you restate this as an answer so that I can accept it? :) Commented Jun 25, 2013 at 21:16
  • you could accept Rex answer although it will be good to mention why map + 2 -> "two" doesn't work (unfortunately, I don't know). Commented Jun 25, 2013 at 21:19
  • 1
    @om-nom-nom - Well, I do know that one. Commented Jun 25, 2013 at 21:21
  • 1
    @om-nom-nom map + 2 -> "two" will give you (map + 2) -> "two": + and -> have same precedence and are left-associative. Commented Jun 25, 2013 at 21:22

1 Answer 1

6

They are exactly the same, thanks to this class in Predef (only partly reproduced here):

final class ArrowAssoc[A](val __leftOfArrow: A) extends AnyVal {
  @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(__leftOfArrow, y)
}
@inline implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x)

So now the question is when will (a,b) syntax be ambiguous where (a -> b) is not? And the answer is in function calls, especially when they're overloaded:

def f[A](a: A) = a.toString
def f[A,B](a: A, b: B) = a.hashCode + b.hashCode
f(1,2)     // Int = 3
f(1 -> 2)  // String = (1,2)
f((1, 2))  // String = (1,2)

Map + in particular gets confused because it's overloaded with a multiple-argument version, so you could

Map(1 -> 2) + (3 -> 4, 4 -> 5, 5 -> 6)

and it thus interprets

Map(1 -> 2) + (3, 4)

as trying to add both 3 to the map, and then 4 to the map. Which of course makes no sense, but it doesn't try the other interpretation.

With -> there is no such ambiguity.

However, you can't

Map(1 -> 2) + 3 -> 4

because + and - have the same precedence. Thus it is interpreted as

(Map(1 -> 2) + 3) -> 4

which again fails because you're trying to add 3 in place of a key-value pair.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for explaining why the parens are required, as suggested by @om-nom-nom.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.