user1615666 user1615666 - 1 month ago 6
Scala Question

scala map in a method argument can not add key-value

In Scala , how to pass a map to a method as a reference object so that I can add key-value to this map. I tried this code, it doesn't work.

var rtnMap = Map[Int, String]()
def getUserInputs(rtnMap: Map[Int, String]) {
rtnMap += (1-> "ss") //wrong here
}


I understand, by default, argument in a method is val, like final in java, it can provide some safety. but at least it should allow us to insert a new entry. do you have any idea ?

Answer

Welcome to functional programming

First of all your use case is possible with mutable map. You have using immutable map because that is by default available in Scala. Everything from the package scala.Predef is by default available in Scala and you don't need to import it by default.

Below code works as excepted.

import scala.collection.mutable.Map

val gMap = Map[Int, String]()

def getUserInputs(lMap: Map[Int, String]) = {
   lMap += (1-> "ss")
}

Below call will change the contents of the gMap

getUserInputs(gMap)

Here is the proof

scala> import scala.collection.mutable.Map
import scala.collection.mutable.Map

scala>
     |     val gMap = Map[Int, String]()
gMap: scala.collection.mutable.Map[Int,String] = Map()

scala>
     |     def getUserInputs(lMap: Map[Int, String]) = {
     |        lMap += (1-> "ss")
     |     }
getUserInputs: (lMap: scala.collection.mutable.Map[Int,String])scala.collection.mutable.Map[Int,String]

scala> getUserInputs(gMap)
res2: scala.collection.mutable.Map[Int,String] = Map(1 -> ss)

scala> gMap
res3: scala.collection.mutable.Map[Int,String] = Map(1 -> ss)

In the last Scala repl notice the contents of the gMap. gMap contains the added item.

General code improvements

Do not use mutable collections unless you have a strong reason for using it.

In case of immutable collections new instance is returned when a operation to change the existing datastructure is done. This way the existing data structure does not change. This is good in many ways. This ensures program correctness and also ensures something called as referential transparency (read about it).

so your program should be ideally like this

val gMap = Map.empty[String, String] //Map[String, String]()

def getUserInputs(lMap: Map[Int, String]) = {
       lMap += (1-> "ss")
}

val newMap = getUserInputs(gMap)

Contents are added to newMap and the old Map is not changed, stays intact. This is very useful because the code holding on to the gMap and accessing the gMap need not be worried about the changes happening to the underlying structure.(Lets say in multi-threaded scenarios, its very useful.)

Keeping the original structure intact and creating the new instance for changed state is the general way of dealing with state in functional programming. So its important to understand this and practice this.

Deprecated syntax and its removed in Scala 2.12

You declared your function like below

def getUserInputs(lMap: Map[Int, String]) { // no = here
  lMap += (1-> "ss")
}

In the above function definition there is no = after the closed parenthesis. This is deprecated in Scala 2.12. So don't use it because Scala compiler gives misleading compilation errors with this function declaration syntax.

Correct way is this.

def getUserInputs(lMap: Map[Int, String]) = { 
 lMap += (1-> "ss")
}

Notice there is = in this syntax.