A few weeks ago, we talked about lambda expressions. We learnt how to use them and some of the advantages they offer.
But, as the old saying goes, all that glitters is not gold. Last April, Jamie Allen came to our Scala meetup in Madrid and spoke about the dark sideof lambda expressions: “What you need to know about lambdas”. In this post we’ll give you an overview of that talk and support the fact that lambda expressions are not to be taken lightly.
First problem: Not reusable.
As a name is not being given to the function, we won’t be able to use it anywhere else in the code.
Second problem: Cannot be tested in isolation.
Provided that it is an ad-hoc function, implemented and embedded at some specific point, it cannot be tested in a separate way.
Third problem: Maintainance.
In general, it is not good practice to use excessive complicated and nested lambda expressions. With them, our code becomes somewhat obscured and thus, difficult to follow and maintain.
List(1, 2, 0, 3, 4).flatMap( x => (1 to x).filter( _ % 2 == 0 ).map( _ * 2 ) ) //List(4, 4, 4, 8)
Fourth problem: error messages.
This problem varies depending on the programming language used. In some cases, error messages will be manageable and in many others, you may feel the desire to slice your wrists off. In our case, in Scala, when there’s an error in an anonymous function we’ll get an error like this:
List(1, 2, 0, 3, 4).map(1 / _) java.lang.ArithmeticException: / by zero at $anonfun$1.apply$mcII$sp(<console>:8) at $anonfun$1.apply(<console>:8) at $anonfun$1.apply(<console>:8) at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) at scala.collection.immutable.List.foreach(List.scala:318) ...
Given that no name was given to the function, the system will throw the error in a $$anonfun. A bit of a WTF, isn’t it?
Fifth problem: Hard time debugging.
Actually, this is not a particular problem of lambda expressions but of the way the code is expressed when using them. If several lambda expressions are written in the same line and there’s an error in any of them, we won’t be able to know which one is causing trouble. That’s why it is highly convenient to separate them in several lines.
List(1, 2, 0, 3, 4).map(_ + 1).filter(_ % 2 == 0).map(_ * 2)
would be better written this way:
List(1, 2, 0, 3, 4).map(_ + 1) .filter(_ % 2 == 0) .map(_ * 2)
Sixth problem: they can encapsulate variables with state
Lambda expressions can access the whole state of their scope. Therefore, they might have access to some mutable value and lead to different results in different execution contexts. Something that we definitely don’t want in functional programming.
Seventh problem …
Their problems can be enclosed into just six statements and lead to inconsistent post titles…
As we have seen, the use of lambda expressions may give rise to a few headaches. That’s why it is recommended to only use those ones which are less complex. In case we want to do something more sophisticated or intricate, the best thing to do is to define a method in order to test and debug it without any trouble. Besides, special precautions shall be taken not to use scope variables that may change its value. We should not deviate from our functional perspective.
I heartily recommend you to take a look at the talk . Many more details were treated in it (this post is just a brief overview) and it might help us to work with lambda expressions in a better way.