gontard
gontard

Reputation: 29520

method reference, covariance contravariance

I just discovered that java 8 allows to reference a method with more specific return type and more general parameters.

import java.util.function.Function;

public class MethodReferences {
    public static Integer function(Object o) {
        return 2;
    }

    public static void main(String[] args) {
        Function<String, Object> function = MethodReferences::function;
    }
}

This is very flexible.

But why they didn't extend this to other cases ?

For example:

import java.util.function.Function;

public class Main {


    public static void main(String[] args) {
        Function<String, Object> function = function();
    }

    private static Function<Object, Integer> function() {
        return new Function<Object, Integer>() {

            @Override
            public Integer apply(Object o) {
                return 1;
            }
        };
    }
}

the compilation fails:

Type mismatch: cannot convert from Function<Object,Integer> to Function<String,Object>

Upvotes: 2

Views: 441

Answers (2)

Rpant
Rpant

Reputation: 1054

Functions should always be contravariant in argument types and covariant in return types.

A2 instanceof A1 and B1 instanceof B2 then

(A1 -> B1) instanceof (A2 -> B2)  // A1 -> B1  means function that takes argument of type A1 and returns value of type B1

This should be true for any programming language where functions are first class citizens. Functions are not first class entities in Java so there is no way language designers could have imposed this variance. ( Obviously that intanceof above doesn't make sense in java because its functions are not instancesof anything. They are just a last ditch effort by java's designers to keep java relevant in the days of big data and apache spark. All of "functional" features are borrowed from scala.

Upvotes: 0

aioobe
aioobe

Reputation: 421090

That's a simple limitation of generics. The type system doesn't know which of Object and Integer are return types and argument types, so it can't do any covariance/contravariance smartness.

If you want to express "A function that takes a supertype of X and returns a subtype of Y" you do Function<? super X, ? extends Y>. And indeed, if you change

Function<String, Object> function = function();

to

Function<? super String, ? extends Object> function = function();

your code compiles. (? extends Object is identical to ? but I wrote it out for clarity)

Upvotes: 10

Related Questions