Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 439
Anil Avatar asked May 27 '12 21:05

Anil


1 Answers

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:

  1. My code can never observe a partially-constructed result
  2. 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?

like image 194
oxbow_lakes Avatar answered Sep 19 '22 20:09

oxbow_lakes