Using immutable collections - scala

I'm in the process of learning Scala, and I have to say that I'm really enjoying it.
I'm porting to Scala a previous Java project of mine, trying to take advantage of the language when I can/know how to (mainly pattern matching and trying to use vals, not into recursion or functions yet).
In the java project, I had an HashMap that started as empty and would get filled by using some methods. Then, of course, I'd use hmap.get(key) to retrieve the objects.
I'd like to use an immutable HashMap this time, but I'm kind of struggling with it! Here's my code:
val recipes = new HashMap[String,Any]()
private def addCrucibleRecipe(tag: String, tagAddon: String, result: ItemStack, cat: Any, aspects: AspectList) {
val recipe = new CrucibleRecipe(some params)
if(recipe.isInstanceOf[CrucibleRecipe]) recipes + (tag -> recipe)
else throw new IllegalArgumentException(tag + " is not a valid recipe!")
}
As you can see, I'm using the + operator, which should return a new HashMap with the previous values and the new one in its tail.
When I call recipes.get(key), however, the list contains Option None.
This means i'm still pointing the old, empty HashMap.
How the hell can I update the reference? And maybe that may sound dumb but I'm really new to functional programming. How is it better than a mutable one?
And if there's an even more functional or efficient way to do this in Scala please tell me, I'm eager to learn :)

Yes, the + method will return a new updated map instance. But you keep a reference here to a mutable value recipes. Unfortunately, that mutable map inherits the methods meant for immutable maps, like +, and so you create a new (mutable but different) map and "throw it away". This is what I mean:
import scala.collection.mutable
val m0 = mutable.Map.empty[String, Int]
m0.put("hello", 1)
val m1 = m0 + ("world" -> 2)
m0.keys // Set(hello) -- this is the "old" map still!
m1.keys // Set(world, hello) -- this is the newly created map
So the correct approach would be to use an immutable map and a var to store it:
var m2 = Map.empty[String, Int] // immutable map
m2 = m2 + ("hello" -> 1)
m2 += ("world" -> 2) // were m2 += ... is short for m2 = m2 + ...
Of course now you have moved the mutable state into having a variable m2 (or var recipes in your example). So you have to define the "breaking point" where you want to store state in your program. For example you could move it one level up:
case class Recipe(ingredients: String*)
case class Recipes(map: Map[String, Recipe]) {
def add(name: String, recipe: Recipe): Recipes =
new Recipes(map + (name -> recipe))
}
val r0 = Recipes(Map.empty)
val r1 = r0.add("pancakes", Recipe("milk", "eggs", "farine"))
Note that in your example addCrucibleRecipe does not have a return value, so you seem to intend to overwrite some state in your containing object. In the case-class example here, I am returning an entirely new copy of that object instead.
You may want to look at these questions:
val-mutable versus var-immutable in Scala
Scala "update" immutable object best practices

Related

What is the impact on memory When we override dataframes and Rdds in apache spark? [duplicate]

What is the difference between a var and val definition in Scala and why does the language need both? Why would you choose a val over a var and vice versa?
As so many others have said, the object assigned to a val cannot be replaced, and the object assigned to a var can. However, said object can have its internal state modified. For example:
class A(n: Int) {
var value = n
}
class B(n: Int) {
val value = new A(n)
}
object Test {
def main(args: Array[String]) {
val x = new B(5)
x = new B(6) // Doesn't work, because I can't replace the object created on the line above with this new one.
x.value = new A(6) // Doesn't work, because I can't replace the object assigned to B.value for a new one.
x.value.value = 6 // Works, because A.value can receive a new object.
}
}
So, even though we can't change the object assigned to x, we could change the state of that object. At the root of it, however, there was a var.
Now, immutability is a good thing for many reasons. First, if an object doesn't change internal state, you don't have to worry if some other part of your code is changing it. For example:
x = new B(0)
f(x)
if (x.value.value == 0)
println("f didn't do anything to x")
else
println("f did something to x")
This becomes particularly important with multithreaded systems. In a multithreaded system, the following can happen:
x = new B(1)
f(x)
if (x.value.value == 1) {
print(x.value.value) // Can be different than 1!
}
If you use val exclusively, and only use immutable data structures (that is, avoid arrays, everything in scala.collection.mutable, etc.), you can rest assured this won't happen. That is, unless there's some code, perhaps even a framework, doing reflection tricks -- reflection can change "immutable" values, unfortunately.
That's one reason, but there is another reason for it. When you use var, you can be tempted into reusing the same var for multiple purposes. This has some problems:
It will be more difficult for people reading the code to know what is the value of a variable in a certain part of the code.
You may forget to re-initialize the variable in some code path, and end up passing wrong values downstream in the code.
Simply put, using val is safer and leads to more readable code.
We can, then, go the other direction. If val is that better, why have var at all? Well, some languages did take that route, but there are situations in which mutability improves performance, a lot.
For example, take an immutable Queue. When you either enqueue or dequeue things in it, you get a new Queue object. How then, would you go about processing all items in it?
I'll go through that with an example. Let's say you have a queue of digits, and you want to compose a number out of them. For example, if I have a queue with 2, 1, 3, in that order, I want to get back the number 213. Let's first solve it with a mutable.Queue:
def toNum(q: scala.collection.mutable.Queue[Int]) = {
var num = 0
while (!q.isEmpty) {
num *= 10
num += q.dequeue
}
num
}
This code is fast and easy to understand. Its main drawback is that the queue that is passed is modified by toNum, so you have to make a copy of it beforehand. That's the kind of object management that immutability makes you free from.
Now, let's covert it to an immutable.Queue:
def toNum(q: scala.collection.immutable.Queue[Int]) = {
def recurse(qr: scala.collection.immutable.Queue[Int], num: Int): Int = {
if (qr.isEmpty)
num
else {
val (digit, newQ) = qr.dequeue
recurse(newQ, num * 10 + digit)
}
}
recurse(q, 0)
}
Because I can't reuse some variable to keep track of my num, like in the previous example, I need to resort to recursion. In this case, it is a tail-recursion, which has pretty good performance. But that is not always the case: sometimes there is just no good (readable, simple) tail recursion solution.
Note, however, that I can rewrite that code to use an immutable.Queue and a var at the same time! For example:
def toNum(q: scala.collection.immutable.Queue[Int]) = {
var qr = q
var num = 0
while (!qr.isEmpty) {
val (digit, newQ) = qr.dequeue
num *= 10
num += digit
qr = newQ
}
num
}
This code is still efficient, does not require recursion, and you don't need to worry whether you have to make a copy of your queue or not before calling toNum. Naturally, I avoided reusing variables for other purposes, and no code outside this function sees them, so I don't need to worry about their values changing from one line to the next -- except when I explicitly do so.
Scala opted to let the programmer do that, if the programmer deemed it to be the best solution. Other languages have chosen to make such code difficult. The price Scala (and any language with widespread mutability) pays is that the compiler doesn't have as much leeway in optimizing the code as it could otherwise. Java's answer to that is optimizing the code based on the run-time profile. We could go on and on about pros and cons to each side.
Personally, I think Scala strikes the right balance, for now. It is not perfect, by far. I think both Clojure and Haskell have very interesting notions not adopted by Scala, but Scala has its own strengths as well. We'll see what comes up on the future.
val is final, that is, cannot be set. Think final in java.
In simple terms:
var = variable
val = variable + final
val means immutable and var means mutable.
Full discussion.
The difference is that a var can be re-assigned to whereas a val cannot. The mutability, or otherwise of whatever is actually assigned, is a side issue:
import collection.immutable
import collection.mutable
var m = immutable.Set("London", "Paris")
m = immutable.Set("New York") //Reassignment - I have change the "value" at m.
Whereas:
val n = immutable.Set("London", "Paris")
n = immutable.Set("New York") //Will not compile as n is a val.
And hence:
val n = mutable.Set("London", "Paris")
n = mutable.Set("New York") //Will not compile, even though the type of n is mutable.
If you are building a data structure and all of its fields are vals, then that data structure is therefore immutable, as its state cannot change.
Thinking in terms of C++,
val x: T
is analogous to constant pointer to non-constant data
T* const x;
while
var x: T
is analogous to non-constant pointer to non-constant data
T* x;
Favoring val over var increases immutability of the codebase which can facilitate its correctness, concurrency and understandability.
To understand the meaning of having a constant pointer to non-constant data consider the following Scala snippet:
val m = scala.collection.mutable.Map(1 -> "picard")
m // res0: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard)
Here the "pointer" val m is constant so we cannot re-assign it to point to something else like so
m = n // error: reassignment to val
however we can indeed change the non-constant data itself that m points to like so
m.put(2, "worf")
m // res1: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard, 2 -> worf)
"val means immutable and var means mutable."
To paraphrase, "val means value and var means variable".
A distinction that happens to be extremely important in computing (because those two concepts define the very essence of what programming is all about), and that OO has managed to blur almost completely, because in OO, the only axiom is that "everything is an object". And that as a consequence, lots of programmers these days tend not to understand/appreciate/recognize, because they have been brainwashed into "thinking the OO way" exclusively. Often leading to variable/mutable objects being used like everywhere, when value/immutable objects might/would often have been better.
val means immutable and var means mutable
you can think val as java programming language final key world or c++ language const key world。
Val means its final, cannot be reassigned
Whereas, Var can be reassigned later.
It's as simple as it name.
var means it can vary
val means invariable
Val - values are typed storage constants. Once created its value cant be re-assigned. a new value can be defined with keyword val.
eg. val x: Int = 5
Here type is optional as scala can infer it from the assigned value.
Var - variables are typed storage units which can be assigned values again as long as memory space is reserved.
eg. var x: Int = 5
Data stored in both the storage units are automatically de-allocated by JVM once these are no longer needed.
In scala values are preferred over variables due to stability these brings to the code particularly in concurrent and multithreaded code.
Though many have already answered the difference between Val and var.
But one point to notice is that val is not exactly like final keyword.
We can change the value of val using recursion but we can never change value of final. Final is more constant than Val.
def factorial(num: Int): Int = {
if(num == 0) 1
else factorial(num - 1) * num
}
Method parameters are by default val and at every call value is being changed.
In terms of javascript , it same as
val -> const
var -> var

How to extend object properties with other in Scala?

I am new to Scala, how to extends one properties value from other object. Like in angular, angular.copy(obj1, obj2);
If I have two objects, obj1, obj2, both having the same property names. obj2's value would be overridden to obj1.
How to achieve this in Scala?
Unlike JavaScript, Scala does not allow you to add new properties to existing objects. Objects are created with a specific type and that type defines the properties on the object. If your objects are implemented as a case class then it is easy to make a copy of an object:
val obj = obj1.copy()
You can also update some of the fields of obj1 during the copy and leave others untouched:
val obj = obj1.copy(count=obj2.count)
This will create a new object with all the same values as obj1 except for the field count which will take the value from obj2.
It has been noted in the comments that in Scala you will typically create new objects from old ones, rather than modifying existing objects. This may seem cumbersome at first but it make it much easier to understand the behaviour of more complex code because you know that objects won't change under your feet.
Note on object in Scala vs JS
Note that object in Scala as a completely different concept from the usage in Javascript.
Scala deliberately is not using Prototype base inheritance.
So in short that this is not possible is a feature not a mssing capability of the language.
see https://docs.scala-lang.org/tour/singleton-objects.html
Solution : Use a Map to simulate protoype base inheritance/composition
You can use a Map to achieve a similar behaviour:
scala> val sayHello = () => "Hello"
sayHello: () => String = <function0>
scala> val obj1 = Map("sayHello" -> sayHello , "id" -> 99)
obj1: scala.collection.immutable.Map[String,Any] = Map(sayHello -> <function0>, id -> 99)
scala> val obj2 = Map("id" -> 1)
obj2: scala.collection.immutable.Map[String,Int] = Map(id -> 1)
scala> obj1 ++ obj2
res0: scala.collection.immutable.Map[String,Any] = Map(sayHello -> <function0>, id -> 1)

Idiomatic way of modifying an immutable collection

I'm interested in understanding the pattern of modifying an immutable collection in the most effective way.
Suppose for example I want to define the following class (an actual implementation may overload the operators, but this is just for illustration). Is this the best way (with respect to performance / safety)?
import scala.collection.immutable.HashMap
class Example[A,B] {
var col = new HashMap[A, B]()
def add(k: A, v: B): Unit = col = col + (k -> v)
def remove(k: A): Unit = col = col - k
}
would this approach be possible as well, in some way I'm missing?
class Example[A,B] extends HashMap[A,B] {
def add(k: A, v: B): Unit = ???
def remove(k: A): Unit = ???
}
The comments above are correct. The idea of immutable data structures exists and there are ways to do it, however, it seems that you may just want to stick with a mutable structure since you have a var anyway.
Check out chapter 17 of the free online pdf of Programming In Scala here where Odersky discusses the designing and building of an Immutable queue.
The gist of it is that you never actually modify the structure that you're trying to change, you just take it in, look at it, and then build a new one based on the old one and whatever it is you're trying to do.
It's the same idea behind the fact that with lists:
val list = List(1,2,3)
1 :: list
println(list)
Will print out List(1,2,3) as opposed to List(1,1,2,3)
While:
val list = List(1,2,3)
val list1 = 1 :: list
println(list1)
is what prints List(1,1,2,3)
Here's a nice slide deck that discusses some popular data structures and their functional counterparts. Functional Data Structures
It sounds like you're trying to make immutable data structures mutable. There are situations where you need to think about performance to be sure, but given that Scala has persistent data structures I'd focus on the use case and not the performance model.
val a = Map("key1" -> "some value")
val b = a + ("key2" -> "some other value")
Now b contains both entries.
If you actually need the mutable structures for your case, just use the mutable.Map.

What are good examples of: "operation of a program should map input values to output values rather than change data in place"

I came across this sentence in Scala in explaining its functional behavior.
operation of a program should map input of values to output values rather than change data in place
Could somebody explain it with a good example?
Edit: Please explain or give example for the above sentence in its context, please do not make it complicate to get more confusion
The most obvious pattern that this is referring to is the difference between how you would write code which uses collections in Java when compared with Scala. If you were writing scala but in the idiom of Java, then you would be working with collections by mutating data in place. The idiomatic scala code to do the same would favour the mapping of input values to output values.
Let's have a look at a few things you might want to do to a collection:
Filtering
In Java, if I have a List<Trade> and I am only interested in those trades executed with Deutsche Bank, I might do something like:
for (Iterator<Trade> it = trades.iterator(); it.hasNext();) {
Trade t = it.next();
if (t.getCounterparty() != DEUTSCHE_BANK) it.remove(); // MUTATION
}
Following this loop, my trades collection only contains the relevant trades. But, I have achieved this using mutation - a careless programmer could easily have missed that trades was an input parameter, an instance variable, or is used elsewhere in the method. As such, it is quite possible their code is now broken. Furthermore, such code is extremely brittle for refactoring for this same reason; a programmer wishing to refactor a piece of code must be very careful to not let mutated collections escape the scope in which they are intended to be used and, vice-versa, that they don't accidentally use an un-mutated collection where they should have used a mutated one.
Compare with Scala:
val db = trades filter (_.counterparty == DeutscheBank) //MAPPING INPUT TO OUTPUT
This creates a new collection! It doesn't affect anyone who is looking at trades and is inherently safer.
Mapping
Suppose I have a List<Trade> and I want to get a Set<Stock> for the unique stocks which I have been trading. Again, the idiom in Java is to create a collection and mutate it.
Set<Stock> stocks = new HashSet<Stock>();
for (Trade t : trades) stocks.add(t.getStock()); //MUTATION
Using scala the correct thing to do is to map the input collection and then convert to a set:
val stocks = (trades map (_.stock)).toSet //MAPPING INPUT TO OUTPUT
Or, if we are concerned about performance:
(trades.view map (_.stock)).toSet
(trades.iterator map (_.stock)).toSet
What are the advantages here? Well:
My code can never observe a partially-constructed result
The application of a function A => B to a Coll[A] to get a Coll[B] is clearer.
Accumulating
Again, in Java the idiom has to be mutation. Suppose we are trying to sum the decimal quantities of the trades we have done:
BigDecimal sum = BigDecimal.ZERO
for (Trade t : trades) {
sum.add(t.getQuantity()); //MUTATION
}
Again, we must be very careful not to accidentally observe a partially-constructed result! In scala, we can do this in a single expression:
val sum = (0 /: trades)(_ + _.quantity) //MAPPING INTO TO OUTPUT
Or the various other forms:
(trades.foldLeft(0)(_ + _.quantity)
(trades.iterator map (_.quantity)).sum
(trades.view map (_.quantity)).sum
Oh, by the way, there is a bug in the Java implementation! Did you spot it?
I'd say it's the difference between:
var counter = 0
def updateCounter(toAdd: Int): Unit = {
counter += toAdd
}
updateCounter(8)
println(counter)
and:
val originalValue = 0
def addToValue(value: Int, toAdd: Int): Int = value + toAdd
val firstNewResult = addToValue(originalValue, 8)
println(firstNewResult)
This is a gross over simplification but fuller examples are things like using a foldLeft to build up a result rather than doing the hard work yourself: foldLeft example
What it means is that if you write pure functions like this you always get the same output from the same input, and there are no side effects, which makes it easier to reason about your programs and ensure that they are correct.
so for example the function:
def times2(x:Int) = x*2
is pure, while
def add5ToList(xs: MutableList[Int]) {
xs += 5
}
is impure because it edits data in place as a side effect. This is a problem because that same list could be in use elsewhere in the the program and now we can't guarantee the behaviour because it has changed.
A pure version would use immutable lists and return a new list
def add5ToList(xs: List[Int]) = {
5::xs
}
There are plenty examples with collections, which are easy to come by but might give the wrong impression. This concept works at all levels of the language (it doesn't at the VM level, however). One example is the case classes. Consider these two alternatives:
// Java-style
class Person(initialName: String, initialAge: Int) {
def this(initialName: String) = this(initialName, 0)
private var name = initialName
private var age = initialAge
def getName = name
def getAge = age
def setName(newName: String) { name = newName }
def setAge(newAge: Int) { age = newAge }
}
val employee = new Person("John")
employee.setAge(40) // we changed the object
// Scala-style
case class Person(name: String, age: Int) {
def this(name: String) = this(name, 0)
}
val employee = new Person("John")
val employeeWithAge = employee.copy(age = 40) // employee still exists!
This concept is applied on the construction of the immutable collection themselves: a List never changes. Instead, new List objects are created when necessary. Use of persistent data structures reduce the copying that would happen on a mutable data structure.

Scala map to HashMap

Given a List of Person objects of this class:
class Person(val id : Long, val name : String)
What would be the "scala way" of obtaining a (java) HashMap with id for keys and name for values?
If the best answer does not include using .map, please provide an example with it, even if it's harder to do.
Thank you.
EDIT
This is what I have right now, but it's not too immutable:
val map = new HashMap[Long, String]
personList.foreach { p => map.put(p.getId, p.getName) }
return map
import collection.JavaConverters._
val map = personList.map(p => (p.id, p.name)).toMap.asJava
personList has type List[Person].
After .map operation, you get List[Tuple2[Long, String]] (usually written as, List[(Long, String)]).
After .toMap, you get Map[Long, String].
And .asJava, as name suggests, converts it to a Java map.
You don't need to define .getName, .getid. .name and .id are already getter methods. The value-access like look is intentional, and follows uniform access principle.
How about this:
preallocate enough entries in the empty HashMap using personList's size,
run the foreach loop,
if you need immutability, return java.collections.unmodifiableMap(map)?
This approach creates no intermediate objects. Mutable state is OK when it's confined to one local object — no side effects anyway :)
Disclaimer: I know very little Scala, so be cautious upvoting this.