4

Say I have the following interface:

@FunctionalInterface
public interface First {
   int fun(int a);
}

and also

@FunctionalInterface
public interface Second extends First {
   default int fun(int a) { fun(a, a); }

   int fun(int a, int b);
}

Then if I have a method somewhere that takes a First I can do, for example:

methodThatTakeFirst(val -> val + 1);

But I also want to be able to pass a Second, like:

methodThatTakeFirst((v1, v2) -> v2 * v2);

However this only works if I cast the lambda like this:

methodThatTakeFirst((Second) (v1, v2) -> v2 * v2);

My question is: is there a way to design this pattern without having to cast the lambdas to the subinterface? Or what would be the most elegant way to handle this scenarios?

Holger
  • 285,553
  • 42
  • 434
  • 765
AndresQ
  • 803
  • 5
  • 19
  • 9
    ...Why would you want to do this? What purpose would this serve? Why wouldn't you just define either `default` functions in your functional interface to handle extra behaviors instead of imposing what looks like unnecessary inheritance? – Makoto Nov 07 '17 at 23:16
  • 7
    Without the cast, there is no way for the compiler to infer that you want a lambda implementation of `Second`. Casting is the best/easiest way to tell the compiler that, so casting *is* the most elegant way to handle this scenario. – Andreas Nov 07 '17 at 23:18
  • 2
    @Makoto good point, assume that First is from a library that cannot be altered, but extended – AndresQ Nov 07 '17 at 23:20
  • 2
    Even if `First` cannot be altered, what is gained by passing an implementation of `Second`, especially a lambda? The only thing that method `methodThatTakeFirst()` can reasonably do with its argument is invoke the `fun(int a)` method, which is defaulted in `Second`. You would be better off defining a concrete implementation of `First`, and passing an ordinary instance of that. – John Bollinger Nov 07 '17 at 23:32
  • sometimes I want to pass a lambda that uses both params, sometimes only one – AndresQ Nov 08 '17 at 17:47

2 Answers2

0

You could overload methodThatTakeFirst, so that it also accepts an instance of Second as an argument, and delegate to methodThatTakeFirst(First first):

void methodThatTakeFirst(First first) {
    // play with first
}

void methodThatTakeFirst(Second second) {
    methodThatTakeFirst((First) second); // casting necessary
}

The cast is crucial, so that the compiler actually delegates to methodThatTakeFirst(First first), otherwise you'd end up with a StackOverflowError.

Whether this is a good design or not, I don't know, but I think it's outside the scope of this question.

fps
  • 33,623
  • 8
  • 55
  • 110
0

Maybe just add another lambda?

  void secondMethod(Second second) {
      methodThatTakeFirst(x-> second.fun(x,x)); 
  }
dehasi
  • 2,644
  • 1
  • 19
  • 31