Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the depth (or limitation if any) for nesting BiFunction

I have been playing with BiFunction (java.util.function). I ran some examples and and I have one question.

Is there a limitation on how many times the operation can be nested with BiFunction? Is it as simple as nesting a hypothetical add(a, b) method as many times as one wants?

e.g. three nested theFunction.apply()

public static int methodContainingMethod
         (int a, int b, int c, BiFunction<Integer, Integer, Integer> theFunction) {
    return theFunction.apply(theFunction.apply(theFunction.apply(a,b),c),c),c);
}

four nested theFunction.apply()

return
  theFunction.apply(theFunction.apply(theFunction.apply(theFunction.apply(a,b),c),c),c),c);

on and on... The number of nesting can go up and on, I tested with nesting the function for over ten times.

I don't have exact requirement as to how many nesting is needed... but I am curious as to how many nesting of such can be done?

like image 262
Nirmal Avatar asked Dec 25 '22 17:12

Nirmal


1 Answers

First of all, that’s not specific to BiFunction in any way. So you are basically asking, how deep you can nest method invocations and the simple answer is that the Java programming language does not specify a limitation per se.

There are technical limitations which may restrict the number but these are, well, technical limitations, not limitation by specification. They might be lifted when the technology evolves without changes in the specification.

As Alain O'Dea has explained, a method’s code size is limited to 65535 bytes or to 65534 bytes if the last instruction ought to be covered by an exception handler. The amount of nested method calls supported by this code size depends on some factors. E.g., you are using an interface and interface method invocation use more bytes than concrete class method invocations (invokevirtual instructions), further, you are using BiFunction<Integer, Integer, Integer> rather than the straight-forward IntBinaryOperator so every invocation involves boxing of the int values which requires additional code.

But there is another technical limitation anyway, the compiler implementation. When trying to compile your example with a higher nesting count, javac ran from the command line terminated with a stackoverflow at 1500 nested invocation, while Netbeans (using the same compiler code as javac) managed to compile 2000 nested invocations before the IDE started to exhibit strange behavior (I guess, it doesn’t handle stack overflows of the compiler/ syntax highlighter very well).

That suggests that the IDE had a higher stack size or other differences in the environmental setup affected the initial stack depth before the expression got parsed. This leads to the conclusion that there is no hard limit in practice. You may be able to write code which one compiler manages to compile without problems whereas another one bails out— not a good idea to max this out.

After all, the equivalent of your question’s code could be written as:

public static int methodContainingMethod(
    int a, int b, int c, BiFunction<Integer, Integer, Integer> theFunction) {

    int value = theFunction.apply(a, b);
    for(int i=0; i<asDeepAsYouWannaGo; i++)
        value=theFunction.apply(value, c);
    return value;
}

though I think, what you have in mind, is more like:

public static int methodContainingMethod(
    IntBinaryOperator theFunction, int first, int second, int... rest) {

  int value = theFunction.applyAsInt(first, second);
  for(int next: rest) value=theFunction.applyAsInt(value, next);
  return value;
}

or

public static OptionalInt methodContainingMethod(
    IntBinaryOperator theFunction, int... arguments) {

  return IntStream.of(arguments).reduce(theFunction);
}
like image 138
Holger Avatar answered Dec 28 '22 06:12

Holger