Wednesday, October 22, 2014

Lambda Expressions - A Comparison between C# and Java

When we came to know about ‘Lambda Expression’ feature in C#, I really became obsessive with it. Using this feature, you can represent an anonymous function in a very crisp and compact way.

C#: "A lambda expression is an anonymous function that you can use to create delegates (Or simply Type safe function references)"

We've explored this feature in C# first, and lately in Java as well. From early on, C# (.NET 3.5) supports delegates and anonymous functions, So the 'Lambda Expression' feature addition, seems quite natural and intuitive in the C# language.

It seems like Java inspired by this enhancement in C#, and introduced their own version of 'Lambda Expression' in latest Java Language (From Java8 onwards). But the problem, is they have to incorporate this to an existing java specification, that revolves around only Class and interfaces. In java there is no concept of 'Delegates Or Function references', hence 'Lambda Expression' feature addition seems less intuitive in terms of implementation.

So
in C#, the lambda expression revolves around 'Delegates' with anonymous functions and in java it is implemented through 'interfaces - that contains a single function prototype' with anonymous classes


Lets see an example below to have a comparison between the two.

Build Your Lambda in Steps

C#
(Delegate/Anonymous function based)
Java
(Interface/Anonymous class based)

1. conceive your concrete function first

Lets take a simple function, that validates an even number. It returns 'true' for an even number and 'false' for an odd number. Let's say this is our concrete function, which we will convert to 'lambda expression' through subsequent steps.
 
C#:
bool IsEven(int number)
{   
    return number % 2 == 0;
}

C# supports functions inside any class. No interface implementation required.

Java:
class EvenValidator implements Proto
{   
    bool IsEven(int number)
    {       
        return number % 2 == 0;   
    }
}

Java requires the function to be enclosed inside a class, that implements the interface prototype 

2. Define a Function Prototype to your concrete function 

C#:
delegate bool Proto(int number);

C# requires a delegate, A type safe function reference. No interface implementations!

Java:
interface Proto
{   
    bool IsEven(int number);
}

Java requires the function prototype to be wrapped inside an interface. Extra overhead!

3. Assign concrete function to Function Prototype 

C#:
Proto objDlgte = new Proto(IsEven);

Clean and natural way of wrapping functions.

Java:
Proto objDlgte = new EvenValidator();

Java does this at the old way. 


4. Anonymous Declaration

As we're referring the function (IsEven) method body, only inside the Function Reference
and nowhere else, why don't we get rid of the function definition altogether, and inline the method body along with the Function reference.

This is exactly an anonymous function or class does. 
C#:
Proto objDlgte = (Proto) delegate(int number)
{
    return number % 2 == 0;
}

C# using Anonymous function.

Java:
Proto objDlgte = new Proto()
{   
    bool IsEven(int number)   
    {       
        return number % 2 == 0;   
    }
}

Java using anonymous class. 


5. Finally arrive at Lambda Expression 

C#:
Proto objDlgte = number => number % 2 == 0;  

Java:
Proto objDlgte = number -> number % 2 == 0;  


6. Usage/Inovke 

C#:
//true
bool isEven = objDlgte(20);

Seems very natural way for invoking a predicate, as a function call.

Java:
//false
bool isEven = objDlgte.IsEven(35);

Less intuitive, as you've to mention both the interface and the method to invoke it. 

Advanced Features - C# (Advantage)  Java (Limitations)

There are some feature limitations to Java, compared to C#. Explained below.

Capturing Variables 
C#:
C# allows us to capture variables inside lambda expressions, defined in the parent scope.
Very convenient.

Java: Java only allows to capture final or effectively final variables inside the lambda expressions, defined in the parent scope.Very Restricting.

Example

C#:
void TestFunction()
{
    int outNumber = 5;
    int evenDivider = 2;
    Proto objDlgte = number =>
    {
       return outNumber % evenDivider == 0;
    };
}

C# support capturing almost all type of variables from outer scope.

Java:
void TestFunction()
{
    final int outNumber = 5;
    final int evenDivider = 2;
    Proto objDlgte = number ->
    {
        return outNumber % evenDivider == 0;
    };
}

You can only refer final/effectively final outer variables inside lambda.So you need to declare the variables as final. A major drawback. 

Conclusion:

Lambda expression is a nice feature addition to high level languages like C# and java. C# lambda expression built with delegate and anonymous functions. Java lately added this feature, inspired from C#. Java's implementation seems not as clean as the way C# does it and having limitations while accessing variables from the declaring scope.

2 comments: