user1615666
user1615666

Reputation: 3451

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 ?

Upvotes: 2

Views: 3231

Answers (3)

Nagarjuna Pamu
Nagarjuna Pamu

Reputation: 14825

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.

Upvotes: 4

Tzach Zohar
Tzach Zohar

Reputation: 37832

To pass a reference to a map and change that map, you'd need to use a mutable Map implementation (the default in Scala is an immutable map, regardless of whether it is declared as a val or a var), so an alternative to @Esardes's answer (one that would also work if rtnMap is not in-scope where getUserInputs is defined) would be:

import scala.collection.mutable

def getUserInputs(map: mutable.Map[Int, String]) {
  map += (1 -> "ss") // mutating "map"
}

val rtnMap = mutable.Map[Int, String]() // notice this can be a val
getUserInputs(rtnMap)
println(rtnMap)
// Map(1 -> ss)

Upvotes: 1

John K
John K

Reputation: 1285

You either wrap your value in an object that you then pass as a parameter, or, if it's available in the scope of your function, you can directly write

def getUserInputs = {
   rtnMap += (1-> "ss") 
}

Upvotes: 0

Related Questions