2

I find it strange that in the List interface are defined 10 methods of(...)

 static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)

instead of just

    @SuppressWarnings("varargs")
    static <E> List<E> of(E... elements){...}

Actually, if I look at the implementation of the varargs version it's even more strange...(a switch on 0,1,2, n elements...)

Any reason for that?

3
  • 2
    Is the source you're looking at online somewhere you could link to? At a guess, I would say performance, but the actual implementation would probably give something more specific to say.
    – IMSoP
    Jan 26, 2021 at 18:19
  • My guess is that the interface was written before Java allowed varargs.
    – user949300
    Jan 26, 2021 at 18:21
  • 2
    @user949300 your guess is wrong, this method was added long after varargs
    – gnat
    Jan 26, 2021 at 18:26

1 Answer 1

6

With absolutely no prior knowledge of the specific case, I would guess: performance.

Given a function with a fixed set of parameters, a compiler can optimise how those parameters are laid out in memory, and even optimise the entire function to a fixed set of processor instructions.

A generalised implementation instead needs machinery for detecting the number of parameters actually passed, collecting them into some intermediate representation, and iterating over them.

Consider an example of sum, in an imaginary language, implemented variadically:

function sum(int[] ...args) {
    local accumulator = 0;
    foreach ( args as next_arg ) {
        accumulator += next_arg;
    }
    return accumulator;
}

Even without knowing the low-level mechanics of passing and allocating variables, we can see that there's a lot going on here. Now compare to implementations with fixed argument lists:

function sum(int a) { return a; }
function sum(int a, int b) { return a + b; }
function sum(int a, int b, int c) { return a + b + c; }
function sum(int a, int b, int c, int d) { return a + b + c + d; }

Here, no intermediate storage needs to be allocated for args and accumulator, and the implementations are easy to map to low-level instructions.

While it's possible for a sufficiently powerful compiler to generate the optimised cases from the generalised one, it's far from easy. So where performance matters more than human convenience, it can be worth hand-crafting at least some of the cases.

2
  • it makes a lot of sense indeed...
    – Glasnhost
    Jan 26, 2021 at 19:00
  • @IMDoP My bad, I mixed up languages when reading the question. Your answer makes sense, it will be a reasonable performance boost.
    – user949300
    Jan 26, 2021 at 19:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.