I don't understand why this works:
val romanNum = immutable.Map(1 -> "I", 2 -> "II", 3 -> "III", 4 -> "IV", 5 -> "V")
val romanNumWith10 = romanNum (10 -> "X")
But this gives an error:
val romanNumWith10 = romanNum (10, "X")
Both (10 -> "X")
and (10, "X")
return a Tuple2.
So both should work, but (10, "X")
doesn't.
By the way, this works:
val romanNumWith10 = romanNum ((10, "X"))
My Scala version is 3.1.2
It seems that Scala sees Int and String separately and not as a Tuple2, but why?
CodePudding user response:
Remember that Scala does not have operators, only methods and lots of sugar syntax.
// Thus, this:
val romanNumWith10 = romanNum (10 -> "X")
// Desugars to:
val romanNumWith10 = romanNum. (10.->("X"))
// And since `10.->("X")` returns a tuple, then it works.
// Whereas, this:
val romanNumWith10 = romanNum (10, "X")
// Desugars to:
val romanNumWith10 = romanNum. (10, "X")
// E.g. trying to call the ` ` method with two arguments; which is an error.
// Finally, this:
val romanNumWith10 = romanNum ((10, "X"))
// Desugars to this:
val romanNumWith10 = romanNum. ((10, "X"))
// Which is again correct.
CodePudding user response:
I'm a bit suprised, it does not infer the right type not even in Scala 3. This dates back from Scala 2 as well. For example, in Scala 2.13.8:
val mymap = Map(2 -> "w")
val x1: (Int, String) = (1, "x")
Doing:
val mymap2 = mymap x1 // ok
compiles but doing:
val mymap3 = mymap (1, "x") // type mismatch
does not.
FWIW, if a method receives a polymorphic argument, you will be tripped when using a tuple there too:
def iCanConsumeAnything[T](x: T) = println(s"Consumed $x !")
Calling it with a tuple:
iCanConsumeAnything(1, "x") // Consumed (1,x) !
compiles ok, as it treats (1, "x")
as a tuple, and not as 2 arguments. But it would confuse anyone into thinking the method receives 2 arguments.
It's generally a bad practice to call the method like this, as well as adding tuple literals to a Map
instead of using the special right arrow ->
syntax.