| d2r diego's weblog |
add(E), but remove(Object)?Martin notes that in Java 5, the new-super-shiny-generics-enabled Collection interface has some inconsistencies. Most notably, the add method is dependent on the specific type for the collection, while remove and contains (most notably) are not. Here are the method contracts: Martin wonders why the discrepancy. I see two options.
Option one is a hilarious story that involves a monkey, a pantsuit, and a cherry cake interfering with the programmer's work and making her/him commit the grievous error for which she/he will feel regret the rest of her/his days. Let's call this the low-probability option. Option two is that the Architecture Astronauts involved in the spec were carried away by the following definition of the remove method : Removes a single instance of the specified element from this collection, if it is present (optional operation). More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if this collection contains one or more such elements. Returns true if this collection contained the specified element (or equivalently, if this collection changed as a result of the call).and this one from the contains method: Returns true if this collection contains the specified element. More formally, returns true if and only if this collection contains at least one element e such that (o==null ? e==null : o.equals(e)).My theory (and hoyven mayven, this is a theory only!) is that because the formal definition involves the use of the equals method and the method specifies an Object (and cannot, given that is the class at the top of the Java object hierarchy, know anything about "E") then the contract for contains and remove also follows with Object rather than E. Sounds reasonable? If anyone has the skinny on this, please pass it on. Alternative theories will also be appreciated. Especially if they involve monkeys (monkey-butlers are also accepted). Categories: soft.devPosted by diego on February 7 2005 at 10:23 PM | TrackBack (0) Comments (please see the comments & trackback policy).
Actually, that's all for backwards compatibility’s sake (I think). You can try to remove anything from the list that you want. Maybe the astronauts got sick of a test "remove(new Object())" failing. Also, it may stem from a slight design problem. If you look at Comparable, the correct signature for using it is "Comparable<? super E>". If they used compareTo() instead of equals(), they might have been able to put a tighter bound on it than Object, but again, backwards compatibility is lost. I've written about generics for a bit, but I still think most of Collection's methods would be cleaner if generics were with Java from the start. More on Comparable's signature: Thanks for the comment Leland (and interesting link). I thought about compatibility as a case, but decided that if compatibility was the issue then add() would also see that problem potentially. Generics should rightly break testing, because you should be testing for tighter bounds on the objects passed, as you say. However, I must admit I was sidetracked with the monkey-scenario and didn't think about it that much. :) Posted by: Diego at February 8, 2005 12:55 AMI don't think it's backwards compatability: it's to do with comparison. You can only add type E to a collection, but when you run remove(Object o) you are not removing the object from the collection, you are actually removing the contents that equals the object the collection. For example, let us say that your type E over-rides the equals() method as follows: public boolean equals(Object o) { In this case, you could pass a String to the remove() method and remove only those E types whose toString() method is equal to the String. Posted by: Ricardo at February 8, 2005 1:16 PMRicardo: that's actually what I described as "option 2". And still nothing involving monkeys... Posted by: Diego at February 8, 2005 1:39 PMYes, but my explanation made less sense. Posted by: Ricardo at February 8, 2005 4:29 PMThat would be an interesting way to filter lists. Too bad you have to make a whole new class to do it... You could have something like public boolean equals(Object o) { to delete all objects in the list that don't contain at least one monkey :). Ruby's mixins are also a way to do this that doesn't require making a new class, but you'd just use "list.select { |x| x =~ /monkey/ }" instead. (or grep in perl, etc) Mixins: I know for fact that it's for backwards compatibility. It's legal to call remove() with an object which is not in the collection; nothing happens in this case. Thus, a type constraint doesn't make sense for remove(). Presumably there is code which would like to be generified, but calls remove() with many types of objects on a collection which actually only contains objects of one type. Without remove(Object), this code could not be converted to use generics. Posted by: Keith Lea at February 8, 2005 5:49 PMWhoops, forgot a ! in there. That deletes all monkey containing objects in the list. That's what the distracted programmer would have wanted to do anyways. You'd use it like this: Post a comment
Copyright © Diego Doval 2002-2007.
|
