Scala: Logging for comprehensions

Learn
2 min readJul 5, 2021

This is a walk from the traditional iterative programming style to “for comprehensions” style in Scala with details about logging within a “for comprehension” at the end.

Traditionally, we had nested iterations that looked like this.

for(int i = 0; i < colors.length; i++) {
for(int j = 0; j < sizes.length;j ++) {
for (int k = 0; k < brands.length; k++) {
.. logic to walk through the car brands..

How to do versus what to do

This iteration faced the argument that this is very complex in that it is describing in too much detail how to iterate through the colors, like it is too much implementation detail leaking into the programmer’s bother.

colors.flatMap( color => sizes.flatMap(size => brands.map( brand => // your logic

This style does take off the iteration nitty gritties, but the iteration style had the advantage of the familiarity. This style is still not as readable. That is where Scala introduces for-comprehensions.

for {
color <- colors
size <- sizes
brand <- brands
} yield // your logic

for comprehensions is an easier piece of code to understand if you discount the fact that the map and flatMap seem more familiar as they appear in multiple languages.

Logging within a for comprehension

While this is bonus material from the context of introducing “for comprehensions”, this is what drove the post in the first place. Traditionally, while writing iterations, it used to be second nature to go in and add log statements into your loops. You would think that you can just easily do that from within for comprehensions. Well, you cannot!

for {
color <- colors
println(“color is “ + color) // *** You cannot do this — compilation error
size <- sizes
brand <- brands
} yield // your logic

for comprehension expects you to have assignment statements. So you need to have your logging code actually return something. So, you juxtapose a method that prints your log statement and returns a type, which does not really need to be used, given that all you wanted to do was to log your execution.

def log[T] ( instance : T, message : String) = {
println(message):
instance;
}

Now, you should be able to log using the below approach.

for {
color <- colors
log1 = log(“color is “ + color)
size <- sizes
log2 = log(“size is “ + size)
brand <- brands
} yield // your logic

--

--