views:

185

answers:

3

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.

+1  A: 

I have no experience with ActionScript, so this may or may not be a workable solution, but in C# I usually do like this:

public class MyGame : ISolvableGame {
    public MyGame clone(){
        // ...
    }

    ISolvableGame ISolvableGame.clone() {
        return this.clone();
    }
}

In other words, I make a "typed" clone method (that does not implement the inteface, since it differs on the return type). Then I make an explicit implementation of the interface method, that will call the typed clone method and return the result. This is a legal move, since MyGame can be cast to ISolvableGame.

Fredrik Mörk
Well, I can definitely do this if the two methods have distinct names, but unfortunately AS3 doesn't allow this sort of overloading... so any caller has to know whether to call clone() or cloneToISolvable(), which is kind of unpleasant. It may be the only way though..
fenomas
+1  A: 

AS3 doesn't allow you to do overloads (more than one function with the same name differentiated by return types or parameter types) only overrides (sub-classes can replace base-class implementations).

e.g.

function foo():int {}
function foo():String {}
function foo(a:String):void {}

Are overloads of the function named foo - you cannot do this in ActionScript. Interfaces are really closer to overrides than overloads in that you are, in a sense, "inheriting" the interface.

// in your specific case you couldn't have these two functions
// defined within the same scope
public function clone():MyGame {}
public function clone():ISolvableGame {}

What you are trying to do is mix the two concepts. You want to overload an interface you are trying to override. As Fredrik's post shows, even in languages that support overloading (of which AS3 is not one) you often can't do both at the same time. The interface forces you to have a function with the exact signature: clone():ISolvableGame and you cannot overload it with an additional clone():MyGame

If you are looking for type-safety you can't get it at compile time but you will be able to get it at run time if you check the return type at the caller.

e.g.

// this will throw if clone does not return an
// object that is cast-able to MyGame
var game:MyGame = MyGame(someObj.clone());

I too would prefer being able to enforce the contract within MyGame but there is no way that I know how.

James Fassett
Thanks for the comment.. please see my update and let me know if you agree with my summary.
fenomas
A: 

Inherited clone methods always has super class as their return type. For example, all the event classes override the clone method of flash.events.Event class that returns an Event object and implement it to return the respective derived class object.

Amarghosh