1

I tried to add an element to a Scala HashMap

val c2 = new collection.mutable.HashMap[String,Int]()
c2 += ("hh",1)

but the above gives me a compile error.

[error]  found   : String("hh")
[error]  required: (String, Int)
[error]   c2 += ("hh", 1)
[error]          ^
[error] /scalathing/Main.scala:5: type mismatch;
[error]  found   : Int(1)
[error]  required: (String, Int)
[error]   c2 += ("hh", 1)
[error]                ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 3 s, completed Sep 1, 2016 1:22:52 AM

The pair I'm adding seems to be of the correct type as demanded by the HashMap. Why do I get a compile error?

1
  • Or c2 += ("hh" -> 1) Commented Sep 1, 2016 at 5:15

1 Answer 1

5

The += operator is overloaded to work with variadic arguments. Therefore when the compiler sees c2 += ("hh", 1) it interprets that as two arguments being passed in, one of which is "hh" and the other of which is 1. You can fix that either by using the -> operator, i.e. c2 += ("hh" -> 1) or enclosing the tuple in another series of parantheses, i.e. c2 += (("hh, 1)).

Slightly gory details below as requested in the comments.

As for how all this works, in the case of mutable collections such as HashMap, += is simply an ordinary method called with operator syntax (i.e. spaces instead of a .) or "infix notation" as the Scala community calls it, as any method in Scala can be. It is provided by the Growable trait which mutable collections mix in. You can see on the documentation for Growable both the single argument += method and the variadic method. In other words the following code would have also worked.

c2.+=(("hh", 1))

Not all +=s are created equal however. += commonly shows up in vars as well. Although it can be called with method syntax ., it's magic syntax sugar implemented directly by the Scala compiler. In particular any nonalphanumeric name followed by an = gets desugared. x $NAME= y becomes x = x.$NAME(y). In this case $NAME= is variadic if and only if $NAME is variadic.

var i = 0
i += 1
i.+=(1) // Also compiles

case class SuperInt(raw: Int) {
  def &*&(x: SuperInt) = SuperInt(raw + x.raw)
}
var x = SuperInt(1)
x &*&= SuperInt(1) // This works
x.&*&=(SuperInt(1)) // As does this
x &*&= (SuperInt(1), SuperInt(1)) // Does not compile because &*& is not variadic
Sign up to request clarification or add additional context in comments.

3 Comments

Good explanation of the failure, and the double parenthesis fix. Perhaps you can improve the answer by reminding that all operators are methods in scala. I almost forgot that when I looked at +=
@Samar added an explanation about +=.
Thank you. Learnt some totally new Scala stuff from your edit.

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.