2

Is there a way to get the compiler to choose the static method reference?

This code fails to compile because there are two methods that satisfy this method reference. Is there a way to hint or cast it so that it resolves the static method reference?

public class Number {
  private final int value;

  public Number(int value) {
    this.value = value;
  }

  public Number add(int x) {
    return operate(Number::add, x);  // <---- compile fail here at Number::add
  }

  private Number operate(BiFunction<Number, Integer, Number> function, int x) {
    return function.apply(this, x);
  }

  public static Number add(Number x, int y) {
    return new Number(x.value + y);
  }

}
prior
  • 339
  • 4
  • 10
  • You don't call static methods with **(::)** in java, just with **(.)** . So where is the operate declaration? – tomrlh Feb 01 '18 at 15:44
  • 6
    Well, `Number::add` *is* ambiguous as both methods have the same functional signature, consuming a `Number` instance and an `int` value. But why on Earth do you use that baroque code structure? What’s the advantage of `return operate(Number::add, x);` over `return add(this, x);`? – Holger Feb 01 '18 at 15:44
  • You're passing a method reference as parameter when it's expecting a `BiFunction function` – KeepoN Feb 01 '18 at 15:49
  • This example is obviously contrived -- I'm just trying to figure out if there's a way to cast a method reference to resolve the ambiguity. The example isn't too far fetched, though -- imagine this had subtract and multiply and divide methods, and they were also static methods -- then this would allow you to reuse the static method code. – prior Feb 01 '18 at 16:07
  • 1
    Even with the addition of more operations, the reason for the detour through the `operate` method is not clear. And, as the ambiguous method references perfectly demonstrate, these `static` methods and the instance methods are functionality equivalent, so there’s no reason to carry both… – Holger Feb 01 '18 at 16:21
  • 3
    just use a lambda expression – fps Feb 01 '18 at 16:42

1 Answers1

4

There is no "collision" :)

The issue is that Number::add is ambiguous (the compiler - the one in eclipse, at least - reports that correctly).

The ambiguous code:

BiFunction<Number, Integer, Number> m = Number::add;

could either mean:

BiFunction<Number, Integer, Number> m = (x,y) -> Number.add(x,y);

or:

BiFunction<Number, Integer, Number> m = (x,y) -> x.add(y);
giorgiga
  • 1,758
  • 12
  • 29
  • 1
    is there a way to remove the ambiguity for the compiler - something akin to casting (without having to create a lambda expression)? – prior Feb 01 '18 at 16:06
  • That would be `(x,y) -> Number.add(x,y)`: let me edit the answer – giorgiga Feb 01 '18 at 16:18
  • 3
    @prior as said [here](https://stackoverflow.com/a/21876077/2711488), no, there is no way. Use a different method (name) or a lambda expression. – Holger Feb 01 '18 at 16:18
  • @prior not editing after all: I thought I could show that `(x,y) -> Number.add(x,y)` generates the same instructions as `Number::add` (w/ no ambiguity), but I am unable to. Anyhow, have trust that javac and/or the JIT will treat them the same way – giorgiga Feb 01 '18 at 16:27