Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is List.remove overloaded the way it is?

Is there historical reasons to the two ambiguous List.remove?

  • List.remove(int)
  • List.remove(Object)

It seems like terrible design to me.
For a List<Integer> it just seems really confusing.

EDIT:

Everybody seems pretty fine with this. Let me precise things a bit.

Let's say I have a List<Boolean>.

Integer idx = Integer.valueOf(2);
list.remove(idx)

Though idx is an object, Java compiles and will remove the item at index 2.

Now if it had been a List<Integer>, the very same code would have called a different method with a totally different behavior.

Let's not talk about what would happen with Generics.

I feel like different behavior implies different names is a precious rule, especially within the same class.

like image 587
fulmicoton Avatar asked Aug 02 '11 13:08

fulmicoton


People also ask

How is a call to an overloaded method resolved?

The process of compiler trying to resolve the method call from given overloaded method definitions is called overload resolution. If the compiler can not find the exact match it looks for the closest match by using upcasts only (downcasts are never done). As expected the output is 10.


1 Answers

First of all:

  • List.remove(int) removes an element at the specified index and
  • List.remove(Object) (or Collection.remove(Object)) removes the specified element.

I'm not sure if this was already known, but for completeness sake, I thought I'd mention it.

An important part to notice is that the API predates generics (and more importantly) auto-boxing by quite a bit (the collections API was introduced in Java 1.2 and auto-boxing was introduced in Java 5).

So when they first designed the API, there was absolutely no way to confuse the two. Even if your List contained Integer objects, it's simple: if you call the method with a primitive argument type (int), then it's the index, if you pass in an Object (even if it's Integer), then you pass in the object to remove.

Granted, it's still not the greatest idea (but quite a few Java APIs are ... less than perfect), but the chance for confusion was much lower back then.

The increased chance of confusion only exists since the int/Integer barrier became less visible thanks to auto-boxing and auto-unboxing.

Sidenote: an important "feature" of the collections API is "short names for commonly used methods". The previous "solution" of Vector/Enumeration had notoriously long names for pretty common operations:

  • Vector.elementAt() vs. List.get()
  • Vector.addElement() vs. Collection.add()
  • Enumeration.hasMoreElements()/nextElement() vs. Iterator.hasNext()/next()
  • Vector.removeElement() vs. Collection.remove()
  • Vector.removeElementAt() vs. List.remove(int)

And the last one are where they probably went a bit too far.

like image 76
Joachim Sauer Avatar answered Sep 24 '22 04:09

Joachim Sauer