views:

95

answers:

4

I just looked up the Set interface and found that it mostly (or completely) only redeclares functions which are already in the Collection interface. Set itself extends Collection, so doesn't that mean that the Set interface automatically has all the functions from Collection? So why are they redeclared then?

For example, Set redeclares this:

/**
 * Returns the number of elements in this set (its cardinality).  If this
 * set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
 * <tt>Integer.MAX_VALUE</tt>.
 *
 * @return the number of elements in this set (its cardinality)
 */
int size();

/**
 * Returns <tt>true</tt> if this set contains no elements.
 *
 * @return <tt>true</tt> if this set contains no elements
 */
boolean isEmpty();

And the declaration in Collection:

/**
 * Returns the number of elements in this collection.  If this collection
 * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
 * <tt>Integer.MAX_VALUE</tt>.
 *
 * @return the number of elements in this collection
 */
int size();

/**
 * Returns <tt>true</tt> if this collection contains no elements.
 *
 * @return <tt>true</tt> if this collection contains no elements
 */
boolean isEmpty();

This seems very redundant to me. Why not just define the Set interface as:

public interface Set<E> extends Collection<E> {}

I think there is no single difference between those interfaces, right?


Of course I am not asking about the different semantics / meaning of Set. I know that. I am just asking about if it technically (i.e. to the compiler) has any difference. I.e., speaking generally:

interface A { void foo(); }
interface B extends A { void foo(); }
interface C extends A {}

Now, is there any difference between A, B or C?


While the contract (i.e. what is said in the documentation) can really be different for some functions (as for add), there is a valid reason to redeclare them: To be able to put a new documentation, i.e. to define the new contract.

However, there are also functions (like isEmpty) which have exactly the same documentation / contract. Why are they also redeclared?

+6  A: 

The answer is in the java6 API for set.

"The Set interface places additional stipulations, beyond those inherited from the Collection interface, on the contracts of all constructors and on the contracts of the add, equals and hashCode methods. Declarations for other inherited methods are also included here for convenience. (The specifications accompanying these declarations have been tailored to the Set interface, but they do not contain any additional stipulations.)"

hvgotcodes
Ah, somehow over read this. But just to clarify: Technically, it doesn't make any difference? It is just that IDEs show the somewhat different documentation of some of the functions to the developer?
Albert
@Albert what doesn't make any difference? There is every difference in the world because Set semantics are different that Collection semantics is different than List semantics and so on..
hvgotcodes
@hvgotcodes: Technical difference = existing working code would break if you use my `Set` definition
Albert
@albert, sorry I am not following you. The interface is not being reproduced verbatim, it is being redefined; i.e. expanded upon to take into account how sets are different.
hvgotcodes
My question was: If you would replace the definition of `Set` by my given suggestion, would existing working code break?
Albert
@albert, no, they do have the same signatures after all.
hvgotcodes
+7  A: 

Technically for the compiler it makes no difference at all.

However, a set cannot have duplicate entries whereas a Collection can. This is worth knowing about.

Because of this, the methods semantics for parameters, return values and what happens can mean different things. Redeclaring also allows the javadoc to become more specific. For example for add():

Set: @return true if this set did not already contain the specified element

Collection: @return true if this collection changed as a result of the call

The meaning for set is more specific.

Even for methods that are not more specific, it enables the javadoc to be nicer. For example, for size() : "Returns the number of elements in this set (its cardinality)." which is closer to the language people used to mathematical sets will understand.

The API documents summarise this by saying: "The Set interface places additional stipulations, beyond those inherited from the Collection interface, on the contracts of all constructors and on the contracts of the add, equals and hashCode methods. Declarations for other inherited methods are also included here for convenience. (The specifications accompanying these declarations have been tailored to the Set interface, but they do not contain any additional stipulations.)"

Nick Fortescue
I don't think this was the question. The question was why identical methods are redeclared (like `size` and `isEmpty`).
musiKk
@musiKk - thanks, I thought I'd mentioned that but I've tried to be more specific now
Nick Fortescue
Ah, so, the main reasons (for most functions) and the basic answer to my question is: "it enables the javadoc to be nicer" :) That is what I have assumed but I asked here on SO just to be sure about that.
Albert
@Albert: It's not just enabling the Javadoc to be nicer... the difference in semantics makes a functional difference, and having a separate interface representing `Set` enables you to restrict a given method to working only with collections that obey the `Set` semantics in a type-safe way by simply declaring `Set` rather than `Collection` as a parameter type.
ColinD
@ColinD: I know the different meaning. But still there is no difference to the compiler. I.e. just the Javadoc is different.
Albert
@Albert: Yes, for the interface itself only the Javadoc is different. I was just pointing out that it does matter to the compiler in the sense that it enables the compiler to check that a method is being given something that at least claims to obey the `Set` semantics.
ColinD
+4  A: 

There is more to a method than its signature.

In this case, the documentation of these methods has been tailored to sets, in terms of pre- and post-conditions, and terminology.

Andy Thomas-Cramer
+1 for "There is more to a method than its signature."
Andrzej Doyle
+2  A: 

They are redeclared because, even if the names are same, they have different meaning. The add method in the Set is a specific implementation of the generic add method in Collection.

The intention is to explicitly specify that the add method os the Set is very different from the add method of Collection.

Why not just define the Set interface as:

public interface Set<E> extends Collection<E> {} 

If it has been done this way, there would be no place where the contract of a Set can be specified. How would I know that by implementing the add method of the Set, I should not allow duplicates?

Nivas
But the contract is just documentation, right? So technically, it wouldn't make any difference? It is just that other developers know about the different meaning?
Albert
_Technically_, seen as pure code, there is no difference at all. _It is just that other developers know about the different meaning ?_: Yes. And this is very important.
Nivas
Ok, thanks for that clarification. Still leaves the question open: What about really identical functions such as `isEmpty` or `size`? Why are those redeclared?
Albert