# Java lambdas

Lambdas in java are based on the idea of `functional interfaces`

which we define
as an interface with a single abstract method.

Here we describe a few of the shortcomings of the functional interface approach taken by java to implement lambdas.

## Syntax

We take the `Predicate`

function defined in the standard library as an
example. Predicate as a functional interface provides the abstract method
`test`

:

```
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
```

Filters are a common use case of predicate functions and can be implemented as follows:

```
static <T> List<T> filter(List<T> xs, Predicate<T> p) {
// ... impl
return xs;
}
```

Syntax wise the reader of the filter function signature is unaware that `p`

is a
lambda construct. Even if the reader has a hint that Predicate might be a function
there’s no information about the “shape” of the function.

We can update the syntax to clearly identify lambdas and their “shape”. For example:

```
static <T> List<T> filter(List<T> xs, T -> Boolean p) {
// ... impl
}
```

It’s now clear that `p`

is a function and that it’s a function that receives a
type `T`

and returns a type `Boolean`

.

## Function application

The `functional interface`

approach also hinders code re-use and function
composition. Currently, the application of a function requires the name of the
abstract method defined in the interface.

For instance, function composition can be declared as follows:

```
static <A, B, C> Function<A, C> compose(Function<A, B> f1, Function<B, C> f2) {
return (A a) -> f2.apply(f1.apply(a));
}
```

The current approach binds the interface `Function`

and its method `apply`

which
decreases code re-use. If we have a function with the same shape in our code
base but with a name other than `apply`

we cannot use `compose`

directly.

On the other hand, this restriction is lifted if function application in lambdas is modified to follow the rules of regular methods.

Piggybacking in our made up lambda syntax from the previous example and removing the interface method during function application we can define composition as follows:

```
static <A, B, C> A -> C compose(A -> B f1, B -> C f2) {
return (A a) -> f2(f1(a))
}
```

After the changes, any function in our code base that satisfies the arity and
types of `compose`

can be composed.

## Package java.util.function

The package `java.util.function`

illustrates the problem of diminished
opportunity for code re-use and the increase of cognitive load.

The documentation for java 8 describes 44 function interfaces. Is the package lacking in different types of functions? Or, 44 functions is all we need?

Take `Function<T, R>`

as a base case. What if we need a function that accepts 2
parameters? `BiFunction<T, U, R>`

is provided. What if we need 3 parameters?
There’s no `TriFunction<T, U, R, S>`

in the standard library and we’re on our
own.

The situation is made worse if we count the implementation specific to primitive
types: `IntFunction<R>, LongFunction<R>`

and etc.

## Partial application

The `functional interface`

approach also does not support partial application of
functions.

Not surprisingly, this won’t compile:

```
BiFunction<Integer, Integer, Integer> f2 = (i, j) -> i + j;
Function<Integer, Integer> f = f2.apply(1);
```

In our hypothetical syntax we can make the case for:

```
Integer -> Integer -> Integer f2 = (i, j) -> i + j;
Integer -> Integer f1 = f2(1);
int r = f1(2); // r is set to 3
```

## Recursion

The `function interface`

approach does play well with recursion. We need some
form of indirection to implement the following idea:

```
void foo() {
Function<Integer, Boolean> f = i ->
i <= 0 ? true : f.apply(i - 1);
// ^ there's no reference to `f`
f.apply(5);
}
```

## Exception propagation

Typed exceptions are also not propagated.

The following code won’t compile:

```
void bar() throws Exception {
Optional.of(10).map(this::baz);
}
int baz(int i) throws Exception {
if (i < 0) throw new Exception("");
return i;
}
```

Our initial assumption is that `baz`

throws an Exception, and thus it would be
correct to expect that `bar`

also throws an exception since baz is used in the
map operation by bar.