Should 'Comparable<T>' be a 'Functional interface'?
Asked Answered
B

4

27

The definition of a functional interface is "A functional interface is an interface that has just one abstract method (aside from the methods of Object ), and thus represents a single function contract."

According to this definition, the Comparable<T> is definitely a functional interface.

The definition of a lambda expression is "A lambda expression is like a method: it provides a list of formal parameters and a body - an expression or block - expressed in terms of those parameters."

Evaluation of a lambda expression produces an instance of a functional interface.

Thus, the purpose of the lambda expression is to be able to create an instance of the functional interface, by implementing the single function of the functional interface. ie. to allow the creation of an instance with the single function.

Let us look at Comparable<T>, is this interface designed for use as a single function? ie. was it designed for the creation of instances with this single function only?

The documentation of Comparable<T> starts with "This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method."

The above sentence makes it clear that the Comparable<T> is not designed to be used as a single function, but is always meant to be implemented by a class, which has natural ordering for its instances, by adding this single function.

Which would mean that it is not designed to be created by using a lambda expression?

The point is that we would not have any object which is just Comparable only, it is meant to be implemented and thus used as an additional function for a class.

So, is there a way in the Java language, by which creation of a lambda expression for Comparable<T> is prevented? Can the designer of an interface decide that this interface is meant to be implemented by a class and not meant to be created as an instance with this single method by use of a lambda expression?

Simply because an interface happens to have a single abstract method, it should not be considered as a functional interface.

Maybe, if Java provides an annotation like NotFunctional, it can be checked by the compiler that this interface is not used for the creation of a lambda expression, eg.

@NotFunctional
public interface Comparable<T> { public int compareTo(T t); }
Browbeat answered 9/8, 2014 at 20:8 Comment(1)
interfaces have no control over how they are implemented. So why should that change for the lambda case?Delois
B
28

A lambda expression can be used where an instance of an interface with a single abstract method is required. You wrote,

Simply because an interface happens to have single abstract method, it should not be considered as a functional interface.

This is exactly correct. Having a single abstract method is a structural property of an interface, one that makes it eligible to be implemented with a lambda. However, whether an interface makes sense or is semantically sensible to be implemented with lambda is a different story. The latter is the purpose of the @FunctionalInterface annotation. When it is present on an interface, it indicates the intent that the interface is useful to be implemented with a lambda.

Notably, the Comparable interface lacks the @FunctionalInterface annotation.

While it's probably nonsensical to use a lambda as a Comparable implementation, there doesn't seem to be any reason to create a mechanism to prevent this from being done. It doesn't seem like doing this would be a source of error, which would be a good reason to develop such a mechanism. By contrast, the @FunctionalInterface annotation is intended to guide programmers in the right direction instead of prohibiting something that is arguably wrong but doesn't seem truly harmful.

Bevis answered 10/8, 2014 at 0:50 Comment(6)
Agree to your comments. How one can suggest from an 'API' to the 'user of API' that a particular Interface is not intended to be used as a 'Functional Interface' except documenting it. In this case can @NotFunctional like annotation can be a useful, where compiler can make sure its not used as lambda expression. Let me know if it makes sense.Browbeat
@Browbeat Documentation is probably best. Whether a lambda is legal is part of the language, and annotations (mostly) do not affect the legality of a program construct. An annotation like @NotFunctional might generate a warning but it wouldn't seem to me to add much value. It's hard for me to imagine how someone could try to use a lambda for Comparable in such a way that it would cause a logic error (as opposed to a compile time error). Someone could try but they'd quickly realize it doesn't make sense. So having the compiler check this somehow doesn't seem worthwhile.Bevis
'nonsensical to use a lambda as a Comparable implementation' - why is it nonsensical, please?Cide
@Andrey A class implements the Comparable interface to allow an instance of the class to be compared to another instance of that class. The comparison is typically done using state (fields) contained within those instances. Since lambdas don't have fields, it's difficult to imagine how a lambda could usefully implement Comparable, even though it's technically possible to write one that does.Bevis
@StuartMarks "even though it's technically possible to write one that does" can you please share any example , just curious how we can do that . i was also trying something wrong and ended here on this thread.Essary
@Essary Consider Comparable<String> c = s -> 0. It's clearly a Comparable and its implementation is a lambda. However, it's not a very good Comparable: c.compareTo("x") returns zero, whereas "x".compareTo(c) won't even compile. (And if you could compile it, calling it would throw ClassCastException.)Bevis
A
8

The issue comes from a subtle difference between a "method" and a "function".

The output value of a function depends ONLY on the arguments that are input to that function.

However the output of a method depends on the arguments that are input to the function but it may also depend on the object's state (instance variables).

That is, any function is a method but not all methods are functions.

For example, the method compare in the interface Comparator depends only on its arguments. However, the method compareTo in the interface Comparable depends on the state of the object to compare to, so it needs to be implemented in a class.

So even Comparable has one abstarct method, semantically it shouldn't be considered as a functional interface.

Astronomical answered 17/4, 2015 at 11:46 Comment(0)
G
3

Well, asides from the discussion how usefull the informative annotation @FunctionalInterface is (and I am happy Java 8 does not require it for lambdas).

Comparable is typically a property of a type and therefore not a good candidate for a functional interface. It is explicitly described as the natural ordering and does not take the two this/that arguments. So this property makes it unlikely any method would operate on a lambda (similliar argument is applicable for nearly all -able interfaces).

So, the collection designers use a second interface for that task: Comparator<T>, and for that a lambda implementing it is a very natural choice.

Guaranty answered 9/8, 2014 at 20:9 Comment(0)
I
0

There is no mechanism to prevent a naive use of an interface not intended to be a functional interface. by having an additional annotation like @NotFunctional, it could be declared explicitly by a designer of an interface, that it should not be used as lambda. And by default if no annotation is specified, it can be considered as good as @Functional, which is currently the case.

Ido answered 11/8, 2014 at 9:21 Comment(1)
:) Smart answer, Shouldn't it be an annotation available in Java 8 API. and Also compiler should give us errors/warnings when we define/use lambda expression of @NonFunctional interfaces ?Browbeat

© 2022 - 2024 — McMap. All rights reserved.