Anonymous function as the name suggests is unnamed or popularly known as lambda functions. In this article, we will approach the idea of lambda functions on how to define them, how to pass them around as an argument and how are they used.
Defining a lambda function
Any lambda function has a pattern of defining the arguments it takes and what you do with those arguments.
(comma seperated arguments) => { method body}
A simple example of a lambda function could be a sum:
(x, y) => x + y
Passing lambda Functions Around
Let's see these lambda functions put to some awesome use which you may not find in most of the programming paradigms.
def printFactory[T](f: Int => T)(times: Int) = {
val valueOfLambda = f(times)
println(valueOfLambda)
}
We define a Factory method where it takes a lambda and the method ensures that the lambda return type is the same as expected(type-safety). This method prints the result of the lambda.
Using lambdas Example
We will see how the factory method gives you an option of defining any lambda that takes an Int and returns anything you define.
// Returns Int
val firstLambda = { (i: Int) =>
100 * i
}
// Returns Double
val secondLambda = { (i: Int) =>
(100.00 / i)
}
// Returns String
val thirdLambda = { (i: Int) =>
val strList = for (j <- 1 to i) yield "hello"
strList.mkString(",")
}
Once we have defined lambdas, we can pass these to our factory method in this way:
val obj = new LambdaFunx
// Calling the Factory
obj.printFactory[Int](firstLambda)(5)
obj.printFactory[Double](secondLambda)(6)
obj.printFactory[String](thirdLambda)(10)
When you set the type T for printFactory method, it enforces you to define a lambda that is of only Int => t type. The code results out to this:
500
16.666666666666668
hello,hello,hello,hello,hello,hello,hello,hello,hello,hello
Find the code here!
Deeper Discussion
Speaking from a strict functional programming point of view, lambdas are everywhere! Let's talk on a small concept of statefulness of a lambda. The lambdas can be divided into two types: Stateful lambdas and Stateless lambdas. Stateful lambdas have state-holding entities defined in the statement body, i.e. mutable variables and mutating operations, for example, a list where you are adding new elements. On the same lines, stateless lambdas which are deprived of all that can cause a state change or in other words, we say capturing values.
Now, why this is important to know this? Anonymous functions in Java or JVM-dependent languages in scala often follow a behaviour that loosely bound to this idea of runtime evaluation of lambda expressions. Now let's think from a JVM's point of view. If you have a lambda expression gives different result every time it is invoked, it will have to create a new instance of the anonymous class for execution. But if the lambda is stateless, JVM reference back to the same instance created avoiding OOM issue. Choose wisely.
Therefore, there's always a caution while using lambdas with parallelStream.
You see the use of lambdas here and there:
val ints = List(1,2,3)
scala> val doubledInts = ints.map(_ * 2)
doubledInts:List[Int]=List(2,4,6)
Conclusion
I have tried to keep the article as simple as possible and it's important to keep the tabs on how many lambdas we make and are they stateful or stateless? If you have any doubts, you can reach us on all social handles or you can comment here or any other social platform. Till then, happy coding!
Comments