Type of method reference and lambda in Java 8 - methods

I'm wondering why methods references and lambdas are not recognized as a Function. Why I need to write
Function<Integer, Integer> fun1 = i -> i+2;
Function<Integer, Integer> fun2 = i -> i*i;
fun1.compose(fun2).apply(4);
instead of
((Integer i) -> i*2).compose((Integer i) -> i+2).apply(4)

Lambda expressions have no intrinsic type; the following is an error:
Object lambda = x -> x;
Lambda expressions are poly expressions, which are expressions whose type is dependent on their context. In particular, a lambda expression derives its type from its target type, which must be a functional interface -- an interface with a single (non-Object) abstract method. The same lambda expression could have multiple types, depending on its target type:
Predicate<String> isEmpty = s -> s.isEmpty();
Function<String, Boolean> isEmpty = s -> s.isEmpty();
The interface Function is not part of the language, nor does it have any magic properties; it is merely an ordinary functional interface, just like Runnable or Predicate or Comparable. There's no reason the compiler could guess that you meant the lambda to target Function rather than some other type.
Further, you don't need to be a lambda to implement Function; you could be a named class or an anonymous class. Lambdas (and method refs) are a syntactically compact means of specifying instances of functional interfaces.

Related

Method Reference - passing Function to method with Consumer argument

I'm learning about Method References from Java 8 and I have difficulties understanding why does this work?
class Holder {
private String holded;
public Holder(String holded) {
this.holded = holded;
}
public String getHolded() {
return holded;
}
}
private void run() {
Function<Holder, String> getHolded = Holder::getHolded;
consume(Holder::getHolded); //This is correct...
consume(getHolded); //...but this is not
}
private void consume(Consumer<Holder> consumer) {
consumer.accept(null);
}
As you can see in run method - Holder::getHolded returns unbound method reference which you can invoke by passing object of type Holder as an argument. Like this: getHolded.apply(holder)
But why it casts this unbound method reference to Consumer when it is invoked directly as an method argument, and it does not doing it when I'm passing Function explicitly?
Two things here, lambda expressions are poly expressions - they are inferred by the compiler using their context (like generics for example).
When you declare consume(Holder::getHolded);, compiler (under the so-called special void compatibility rule) will infer it to Consumer<Holder>.
And this might not look obvious, but think of a simplified example. It is generally more than ok do call a method and discard it's return type, right? For example:
List<Integer> list = new ArrayList<>();
list.add(1);
Even if list.add(1) returns a boolean, we don't care about it.
Thus your example that works can be simplified to:
consume(x -> {
x.getHolded(); // ignore the result here
return;
});
So these are both possible and valid declarations:
Consumer<Holder> consumer = Holder::getHolded;
Function<Holder, String> function = Holder::getHolded;
But in this case we are explicitly telling what type is Holder::getHolded,, it's not the compiler inferring, thus consume(getHolded); fails, a Consumer != Function after all.
Java 8 introduced 4 important "function shapes" in the package java.util.function.
Consumer -> accepts a method reference (or a lambda expression) that takes one argument but doesn't return anything
Supplier -> accepts a method reference (or a lambda expression) that takes no argument and returns an object.
Function -> accepts a method reference (or a lambda expression) that takes one argument and returns an object.
Predicate -> accepts a method reference (or a lambda expression) that takes one argument and returns a boolean.
Read the Java docs for more detail.
To answer your question on why the first one works but the second one errors out, read following:
The second statement
consume(getHolded);
doesn't work because the type of the argument getHolded is Function<Holder, String> whereas the consume method expects an argument of type Consumer<Holder>. Since there is no parent-child relationship between Function and Consumer, it requires an explicit cast without which the compiler rightly errors out.
The first statement
consume(Holder::getHolded);
works because the method getHolded is declared as public String getHolded() meaning that it doesn't take any argument and returns a String. As per the new void compatibility rule, void types are inferred as the class containing the referenced method. Consider the following statement:
Consumer<Holder> consumer = Holder::getHolded;
This is a valid statement even though the method getHolded doesn't accept any arguments. This is allowed to facilitate inferring void types. Yet another example is the one you have mentioned yourself:
Function<Holder, String> getHolded = Holder::getHolded;
This is also a valid statement where you have said that the function object getHolded is a Function that returns String and accepts a type Holder even though the assigned method reference doesn't take any argument.
Sharing just a summary of the four types of Method References under the hood:
Reference to a static method:
Type::staticMethod ===>>> x -> Type.staticMethod(x)
Reference to an instance method of a particular object:
instance::instanceMethod ===>>> x -> instance.instanceMethod(x)
Reference to an Instance Method of an Arbitrary Object of a Particular Type:
Type::instanceMethod ===>>> x -> x.instanceMethod() OR (x, y) -> x.instanceMethod(y)
Reference to a constructor:
Type::new ===> x -> new Type(x)

Why is it possible initialize java.util.function.Consumer with lambda that returns value? [duplicate]

I am confused by the following code
class LambdaTest {
public static void main(String[] args) {
Consumer<String> lambda1 = s -> {};
Function<String, String> lambda2 = s -> s;
Consumer<String> lambda3 = LambdaTest::consume; // but s -> s doesn't work!
Function<String, String> lambda4 = LambdaTest::consume;
}
static String consume(String s) { return s;}
}
I would have expected the assignment of lambda3 to fail as my consume method does not match the accept method in the Consumer Interface - the return types are different, String vs. void.
Moreover, I always thought that there is a one-to-one relationship between Lambda expressions and method references but this is clearly not the case as my example shows.
Could somebody explain to me what is happening here?
As Brian Goetz pointed out in a comment, the basis for the design decision was to allow adapting a method to a functional interface the same way you can call the method, i.e. you can call every value returning method and ignore the returned value.
When it comes to lambda expressions, things get a bit more complicated. There are two forms of lambda expressions, (args) -> expression and (args) -> { statements* }.
Whether the second form is void compatible, depends on the question whether no code path attempts to return a value, e.g. () -> { return ""; } is not void compatible, but expression compatible, whereas () -> {} or () -> { return; } are void compatible. Note that () -> { for(;;); } and () -> { throw new RuntimeException(); } are both, void compatible and value compatible, as they don’t complete normally and there’s no return statement.
The form (arg) -> expression is value compatible if the expression evaluates to a value. But there are also expressions, which are statements at the same time. These expressions may have a side effect and therefore can be written as stand-alone statement for producing the side effect only, ignoring the produced result. Similarly, the form (arg) -> expression can be void compatible, if the expression is also a statement.
An expression of the form s -> s can’t be void compatible as s is not a statement, i.e. you can’t write s -> { s; } either. On the other hand s -> s.toString() can be void compatible, because method invocations are statements. Similarly, s -> i++ can be void compatible as increments can be used as a statement, so s -> { i++; } is valid too. Of course, i has to be a field for this to work, not a local variable.
The Java Language Specification §14.8. Expression Statements lists all expressions which may be used as statements. Besides the already mentioned method invocations and increment/ decrement operators, it names assignments and class instance creation expressions, so s -> foo=s and s -> new WhatEver(s) are void compatible too.
As a side note, the form (arg) -> methodReturningVoid(arg) is the only expression form that is not value compatible.
consume(String) method matches Consumer<String> interface, because it consumes a String - the fact that it returns a value is irrelevant, as - in this case - it is simply ignored. (Because the Consumer interface does not expect any return value at all).
It must have been a design choice and basically a utility: imagine how many methods would have to be refactored or duplicated to match needs of functional interfaces like Consumer or even the very common Runnable. (Note that you can pass any method that consumes no parameters as a Runnable to an Executor, for example.)
Even methods like java.util.List#add(Object) return a value: boolean. Being unable to pass such method references just because that they return something (that is mostly irrelevant in many cases) would be rather annoying.

Method references to raw types harmful?

The code below contains a reference to Enum::name (notice no type parameter).
public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), Enum::name);
}
public static <T, R> ColumnType<T, R> simpleColumn(BiFunction<JsonObject, String, T> readFromJson,
Function<T, R> writeToDb) {
// ...
}
Javac reports a warning during compilation:
[WARNING] found raw type: java.lang.Enum missing type arguments for
generic class java.lang.Enum
Changing the expression to Enum<T>::name causes the warning to go away.
However Idea flags the Enum<T>::name version with a warning that:
Explicit type arguments can be inferred
In turn Eclipse (ECJ) doesn't report any problems with either formulation.
Which of the three approaches is correct?
On one hand raw types are rather nasty. If you try to put some other type argument e.g. Enum<Clause>::name will cause the compilation to fails so it's some extra protection.
On the other hand the above reference is equivalent to e -> e.name() lambda, and this formulation doesn't require type arguments.
Enviorment:
Java 8u91
IDEA 15.0.3 Community
ECJ 4.5.2
There is no such thing as a “raw method reference”. Whilst raw types exist to help the migration of pre-Generics code, there can’t be any pre-Generics usage of method references, hence there is no “compatibility mode” and type inference is the norm. The Java Language Specification §15.13. Method Reference Expressions states:
If a method or constructor is generic, the appropriate type arguments may either be inferred or provided explicitly. Similarly, the type arguments of a generic type mentioned by the method reference expression may be provided explicitly or inferred.
Method reference expressions are always poly expressions
So while you may call the type before the :: a “raw type” when it referes to a generic class without specifying type arguments, the compiler will still infer the generic type signature according to the target function type. That’s why producing a warning about “raw type usage” makes no sense here.
Note that, e.g.
BiFunction<List<String>,Integer,String> f1 = List::get;
Function<Enum<Thread.State>,String> f2 = Enum::name;
can be compiled with javac without any warning (the specification names similar examples where the type should get inferred), whereas
Function<Thread.State,String> f3 = Enum::name;
generates a warning. The specification says about this case:
In the second search, if P1, ..., Pn is not empty and P1 is a subtype of ReferenceType, then the method reference expression is treated as if it were a method invocation expression with argument expressions of types P2, ..., Pn. If ReferenceType is a raw type, and there exists a parameterization of this type, G<...>, that is a supertype of P1, the type to search is the result of capture conversion (§5.1.10) applied to G<...>;…
So in the above example, the compiler should infer Enum<Thread.State> as the parametrization of Enum that is a supertype of Thread.State to search for an appropriate method and come to the same result as for the f2 example. It somehow does work, though it generates the nonsensical raw type warning.
Since apparently, javac only generates this warning when it has to search for an appropriate supertype, there is a simple solution for your case. Just use the exact type to search:
public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), T::name);
}
This compiles without any warning.

How do I use [TypeArguments] with a constructor reference in Java 8?

Section 15.13 of the Java Language Specification for Java 8 describes this form of the method reference syntax for creating a constructor reference:
ClassType :: [TypeArguments] new
For example:
String s = "abc";
UnaryOperator<String> test0 = String::new; // String(String) constructor.
String s0 = test0.apply(s);
System.out.println("s0 = " + s0); // Prints "abc".
char[] chars = {'x','y','z'};
Function<char[], String> test1 = String::new; // String(char[]) constructor.
String s1 = test1.apply(chars);
System.out.println("s1 = " + s1); // Prints "xyz"
That all works fine, but it seems that absolutely anything (excluding primitives) can be also supplied for the [TypeArguments] and everything still works:
Here's a silly example to prove the point:
Function<String, String> test2 = String::<LocalDateTime, Thread[]>new; // Compiles !!!???
String s2 = test2.apply("123");
System.out.println("s2 = " + s2); // Prints "123"
A few questions arising:
[1] Since the String class doesn't even use generics, is it valid that the compiler allows the creation of that test2 constructor reference with those meaningless [TypeArguments]?
[2] What would be a meaningful example of using [TypeArguments] when creating a constructor reference?
[3] Under what conditions is it essential to specify [TypeArguments] when creating a constructor reference?
1 15.13.1. Compile-Time Declaration of a Method Reference
If the method reference expression has the form ClassType :: [TypeArguments] new, the potentially applicable methods are a set of notional methods corresponding to the constructors of ClassType.
...
Otherwise, the candidate notional member methods are the constructors of ClassType, treated as if they were methods with return type ClassType. Among these candidates, the methods with appropriate accessibility, arity (n), and type argument arity (derived from [TypeArguments]) are selected, as specified in §15.12.2.1.
JLS 15.12.2.1. Identify Potentially Applicable Methods
This clause implies that a non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. Indeed, it may turn out to be applicable. In such a case, the type arguments will simply be ignored.
2 Whenever a constructor is parameterized. I've never stumbled upon one.
public class Foo {
public <T> Foo(T parameter) {
...
Function<String, Foo> test = Foo::<String>new
3 When the compiler can't infer the type.

Allocating a memberless type at runtime v.s. binding at compile time

Here's two F# scenarios. I have an abstract class:
type IAbstractObj =
abstract DoSomething : bool -> bool
Scenario 1:
I implement the interface into a type:
type ConcreteObj =
interface IAbstractObj with
member this.DoSomething bool = true
This is then used in the application by instantiation:
let foo = new ConcreteObj();
Scenario 2:
I bind an instance of the type with a let binding and use it as a 'free function holder':
let ConcreteObj = {
new IAbstractObj with
member this.DoSomething bool = true
}
And use it as such:
let foo = ConcreteObj
What are the differences between these usages? In either case, the types don't need to hold any additional runtime state.
Would there be a performance difference (miniscule)? With modules containing 'let' bindings, is memory only allocated to the bindings that are actually evaluated in other parts of the application?
Would scenario 1 allocate a small amount of memory to hold a pointer to the instance (even though it is stateless)?
It's fairly important for my application. I use many interfaces for validators and serializers that dont hold any instance state. With my C# background, I'm used to just having to create an instance of a class that inherits an interface even if it has a paramaterless constructor and is clearly only a holder of essentially static functions.
There is a more idiomatic option than either of those. Instead of creating a new type for each option, simply create a record type which has two members which are functions. You nearly defined it yourself in the comments:
type serializer<'a, 'b> =
{ Serialize : 'a -> 'a Option
Deserialize: 'b -> 'b Option}
let concrete = { Serialize = (fun (x)->Some(x)); Deserialize = (fun (x)->Some(x)) }
So whatever is consuming this should take a serializer.
The principal difference between the two is that an object expression has the static type of the interface or abstract class it implements. Whereas, class-based interface implementation is explicit and requires casting to access interface members.
For trivial interface implementations, an object expression is generally a better choice than a class.
(FWIW, I think your performance concerns are inconsequential.)

Resources