I recently found out that I can have two interfaces, one containing a method with the same signature as a method in the other interface. And I can have an interface or class that implements both of afore-mentioned interfaces. So the descendant class/interface implicitly implements two different methods as one method.
Why is this allowed in Java?
I can see numerous problems arising from this. Eclipse, for example, can only find out about implementations for one interface method, but for the second one it doesn’t show any implementations at all. Also, I believe that there would be problems with automatic refactoring, like when you want to change the signature of the method in one of the interfaces and the IDE will be unable to correctly change that signature in all implementations (since they implement two different interfaces, and the IDE cannot tell which interface method the implementation is referring to.)
Why don’t just make a compiler error like ‘interfaces method names clashes’ or something like that?
3
There is no reason why this should be forbidden. The only point of an interface is to ensure that a method with particular signature exists in each implementing class. This is satisfied by any implementing class even if the condition is posed twice.
Granted, when you write an interface you presumably expect a certain meaning for the action of invoking the method, and presumably you document it above the declaration in the interface, but that is not the concern of the compiler. It cannot check whether the implementing class does the right thing, only whether it copies the signature exactly. Asking “Why doesn’t the compiler forbid one method to satisfy two interface declarations?” boils down to “why doesn’t the compiler prevent me from implementing the wrong semantics when I implement an interface?”, and the answer to that question is much easier to see: because it can’t! (If the compiler were able to judge your method implementation and forbid it if it contained a bug, then we wouldn’t need programmers in the first place, we’d need only the specifications and the compiler.)
Obviously we would like it if implementing an interface guaranteed that the implementing class does the right thing, but that’s not something that interfaces can do for you. In fact, I’d argue that it would be a bad thing to add a feature to the compiler that might give the impression that it is!
1
Why should that be a bad thing?
Just because it makes refactoring in Java harder, doesn’t mean it is bad. For example, if I want refactoring in C++, it would be almost impossible in cases of some heavy template-dependent code, since the templates are Turing-complete. And in C++, templates are like the best thing in the language. Should we remove them to make refactoring easier?
The major concern in language design should be for the language to make the life/work of its users easier. I think your rule is too narrow, and not intuitive at that.
Plus this strikes me as too stringent: say I am using two libraries, closed source (as much as it’s possible in Java anyway). I have a class that needs to implement two interfaces, one from each library. But the interfaces have a method with the same name/signature.
By your logic, I’m doomed! And to think of it, the library designers did nothing wrong: is it their job to know all method names in all classes of all other libraries? There is no chance to ensure this, even if you try hard…
You might say that this should be split in two classes, but what if the library designers actually meant the same thing with the two methods? Having a class implement both interfaces is the proper way in this situation.
4
Technically there is nothing wrong with this from the language point of view. There would have been problems if you have inherited from two classes, where the base classes are implemented.
If you consider it a design issue where one interface has one contract for that method and the other interface has other contract then not allowing it would not solve the issue. The end solution would be to disallow multiple inheritance.
Regarding the automatic refactoring problem, there is a problem with the IDE (Intellij has the same behavior); it should ask you which base method do you want refactored.
2
Well, I’m more of a .Net guy but I though of chipping in.
So, forgive me if the syntax is incorrect.
Suppose you have to talk to different two DBs in your class. Each DB has a different interface.
interface IOldDB
{
string GetConnectionString()
void OpenConnection()
void OpenSession()
...
}
interface IOldDB
{
string GetConnectionString()
bool Connect()
void NewSession()
...
}
Making it illegal would mean that I’d have to have two classes, one per Interface. All because one “apparently” conflicting method.
And if the methods of some interfaces have the same signature and you are implementing both, they are probably there for the same reason, right? If not, you’re probably violating the SRP. Even if you are violating it, there’s no reason for the compiler to stop you.
By the way, if I’m not mistaken, the compiler will throw an error if the signature of any of the methods conflict. Trying to implement those two interfaces
interface IAnotherDB
{
void GetConnectionString(string cs)
}
interface IYetAnotherDB
{
void GetConnectionString(string ConnectionString)
}
Will throw an error.
In .Net you could do that, by Implementing the Interface explicitly.
Instead of:
public void GetConnectionString(string ConnectionString)
You could do
IAnotherDB.GetConnectionString(string cs)
IYetAnotherDB.GetConnectionString(string ConnectionString)
And go on.
Hope it helps.
2
It seems like it would imply a certain lazyness, but not really be a problem.
If you have two interfaces, each with methods you need for a given scenario then you either need to have interfaces implement each other, cast between them (yuck) or have them declare each others methods redundantly.
I guess I could imagine cases where extending wasn’t practical or possible, so perhaps in that case you’d go for the option you are describing.
The better way to do it would probably be interface inheritance where one interface might implement 2 or 3 more specific interfaces, but this would annoy many people…