I'm writing an interface that requires classes to implement a clone() method. My naive approach to this went along the following lines:
public interface ISolvableGame {
function clone():ISolvableGame;
//...
}
elsewhere:
public class MyGame implements ISolvableGame {
public function clone():MyGame {
// ...
}
}
I had supposed that this sort of signature would be legal, because MyGame.clone()
returns an instance of a class that implements ISolvableGame, which seems to me to satisfy the contract in the interface. However, code like the above generates a compile error, referring to the fact that MyGame.clone()
has a different signature than the one specified in the interface.
My question is thus, how can I make an interface requiring a clone method if the implemented method must exactly match the signature in the interface? Obviously making the interface more specific wouldn't make any sense. But if I made the implemented method less specific (i.e. if I typed MyGame.clone()
as returning ISolvableGame
), other users of that clone method would no longer know what they were getting.
Do I need two versions of the clone method, one typed as ISolvableGame
to satisfy the interface and another typed as MyGame
for use within the class? Or is there a better approach?
Note: I'm working in ActionScript3 (a Java-like language that implements the ECMA4 spec). I tagged this as language-agnostic in the assumption that AS3 isn't unique in how it treats interfaces. But if my sample code above would work in other languages, then my problem may be specific to my language.
Update: It occurred to me to examine how the core libraries of my language deal with this. For example, there is an IEventDispatcher
interface, which defines a method dispatch():Event
- so any class that dispatches a subclass of Event
cannot implement IEventDispatcher
, which is ultimately similar to my problem.
The core libraries deal with this by instead having such classes inherit from a class EventDispatcher
, which exists for the purpose of implementing IEventDispatcher
. Thus gaining compile-time type safety, but at the cost of rather diluting the point of using an interface in the first place, since one usually prefers interfaces to avoid problems posed by inheritance.
I'm thinking that my choices are:
- Rely ultimately on inheritance, as the core libraries do
- Implement two methods as Frederik describes, with different names
- Sacrifice compile-time type safety as James describes
Answer: In the end, I went with the option of having the interface specify a cloneToSolvable
method - i.e., the interface specifies a method to clone to the interface type, and implementing classes must have that method in addition to any more specifically typed clone method they might have. This seemed to me the least unpleasant of the options.