Internal Vs External iteration

Most of the time we need to iterate through a list, we end doing the same. We tend to specify every detail, we code every step of the way. But is there any other way ? Well there is…​it’s call internal iteration.

The point here is that We should be taking care on the logic of filtering and transformation and not how to loop through the collection, Don’t you thing ?

There are some reasons I would recommend you to start using internal iteration:

  • Is more concise and clear

  • Reusability

  • Composition

  • Internal optimizations

More concise

Let’s say we have a list of mercenaries in lower case and we want to get their names in upper case. Well no problem…​That is what is should look like in old-fashioned Java code:

External Iteration: Java style
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_1,indent=0]
  • We have to remember to create the collection to store the transformed names.

  • Then we should know how the iteration is done

  • Finally to add explicitly every transformed name into the new collection.

Maybe Groovy is more concise and less verbose…​hell yeah but you can do it wrong either.

External Iteration: Groovy style
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_2,indent=0]

"That’s not what I signed for!!!" you may think. Don’t worry Groovy has a lot more to offer. Collections in Groovy have many useful method to loop through them filtering and collecting transformed values without having to specify how a collection should be traversed.

Internal Iteration: Groovy
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_3,indent=0]

This example shows how you can loop through a collection in Groovy in a declarative way. You can almost read "I want to collect the upper-case-version of the expendable collection" can’t you ?

Of course you can embed the closure expression as a parameter instead of declaring the expression and then passing it to the collect method

Internal Iteration: Groovy
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_4,indent=0]

But later on you’ll see that sometimes is better not to use the Closure expression directly if you want to keep your code reusable.

Reusability

Imagine we had a method looping through a collection to sum all numbers less than 20.

Internal Iteration: Groovy
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_5,indent=0]

Now we want to get all numbers from 20 to 100

Internal Iteration: Groovy
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_6,indent=0]

And now…​you know what ? forget it :P

There should be a better way of refactoring this behavior. There are two main actions when trying to solve these type of problems:

  • Filtering data

  • Transforming data

And when talking about Groovy and collections this means to use find or findAll when trying to filtering data and collect for transforming data.

Back to the prolem, while the transformation applied to the data is the same the filtering applied is different. Lets see how our reusable method should look like:

Internal Iteration: Filter + Transformation
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_7,indent=0]
1 First we pass the collection we want to transform. We say transform deliberately, we don’t want to mutate the collection but to create a new one for applying a given action. This case to sum all numbers of that new collection
2 We want to get certain numbers to add them up. By default if no filter given then apply to all ({ it }).
3 We’re using Groovy’s collection behavior to apply the given filter to get the new collection and then sum all numbers in that collection.

And how to use it for different filters:

Internal Iteration: Reuse of functions
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_8,indent=0]

That’s great but the previous example shows us a way of reusing behavior through the use of methods. But Does it mean it will be forcing us to create a method every time we would like to reuse a certain behavior ? That would lead us to create a lot of methods don’t you think ?

Functional programming teach us that behavior is not limited to methods of an object. When talking about behavior we will be talking of functions in a more general way.

Functions are more powertful in the way that they can be modified, passed as a parameter to other functions, and still can be used as the methods we normally use. In Groovy such type of functions are called closures.

Although we will be talking about closures deeper in its own chapter lets say for now that they’re extremely useful to reuse behavior.

What if I want to use the same method with the same type of filter several times in the same method. That would be a lot of boiler plate code. A lot of code to maintain and repeat. Sounds too dirty…​ and looks worst :P

Internal Iteration: Reusability limited to methods ?
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_9,indent=0]

What can I do ? Well let’s say that Groovy methods could be transformed into closures…​ How ? As I said earlier functions / closures can be assigned and be passed as parameters.

Internal Iteration: Reusability limited to methods ?
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_10,indent=0]
1 We assign the closure representing the filter to a given variable
2 Then we pass the closure as parameter to filter numbers

And also I said methods in Groovy can be transformed to closures:

Internal Iteration: Reusability limited to methods ?
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=external_iteration_11,indent=0]
1 We are creating a new function with a fixed type of filter
2 We have created a new function that sums all numbers greater than 20 and less than 200 for the collection passed as parameter
If the expression this.&sum.rcurry sounds like chinese to you just take that this expression is only saying: I want to get a new function with the first parameter from the right with the following value { it > 20 && it < 100}. Anyway I recommend you to review the chaper dedicated to closures.

Composition

Today’s specifications may change. Lets say I want to trim all strings coming from a given collection. But then my boss comes and tells me he wants all words uppercase.

Looping more than neccessary
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=composition_1,indent=0]

The problem is that we’re looping the word list twice

1 first to trim all words and then
2 we’re looping again to convert every word to uppercase.

With composing both behaviors we can apply both at once for every word. We will be saving a loop for every new transformation. That’s worth knowing right ?

Composing behavior
Unresolved directive in 3_iteration.ad - include::{testDir}/groovyfp/exit/ExternalIterationIsEvilSpec.groovy[tags=composition_2,indent=0]
1 This is a special notation for composing closures. The composition has to be read from right to left. The first behavior to be taken is the first on the right.