views:

99

answers:

2

Imagine I have a game with a base Entity class, with an init method that takes no arguments. Now I have a Wizard class, but I want to pass in 2 parameters, say speed and strength. In AS3 (and I believe Java and C#) I will not be allowed to do this - it is an "incompatible override" because the method signatures won't match. Now I could just make an "initWizard" method instead, but then I have the problem of the init method of each class potentially having different names.

I need solutions that work in AS3, Java or C#.

+1  A: 

Not sure I understood your question correctly. But the following compiles in Java:

public class A {
    public void init(int a) {}
}

public class B extends A {

    public void init( int a, int b )
    {
        super.init( a );
    }
}

Though I agree that B#init(int,int) is not an override of A#init(int), and B#init(int) can still be called. You can not really hide the existence of B#init(int), at best, you could override it in B and let it throw an exception if it is called.

Is it however so a big problem? The method signature capture only part of the contract of how a class must be used. If you want to shield your code a bit more, you could use a factory method to create instances of A or B and make init protected.

public class A {
    protected void init(int a) {}

    static public A create( int a)
    {
        A o = new A();
        o.init( a );
        return o;
    }
}

public class B extends A {

    protected void init( int a, int b )
    {
        super.init( a );
    }

    static public B create( int a, int b)
    {
        B o = new B();
        o.init( a, b );
        return o;
    }
}
ewernli
Thanks for this - basically I just wanted to know if I was crazy or AS3 was missing something important. This time the answer is that AS3 is missing something important.
Iain
+6  A: 

AS3 doesn't support method overloading, but frankly, method overloading is just a syntactic sugar and usually only introduces ambiguity and inconsistency.

In Java, a method is determined by its name and its signature, in AS3, only by its name, but semantically, there's only little difference between

protected void init( int a )
protected void init( int a, int b )

and

protected void init1( int a )
protected void init2( int a, int b )

In AS3, the can be only one method per name and only one constructor per class. However, constructors need not have compatible signatures. In AS3 you'd solve the problem like this:

package {
 class A {
  private var a:int;
  public function A(a:int) {
   this.a = a;
  }
  // ... probably some meaningful methods here :)
 }
}
package {
 class B extends A {
  private var b:int;
  public function B(a:int, b:int) {
   super(a);
   this.b = b;
  }
  // ... probably some other meaningful methods here as well :D
 }
}

You also avoid the problems in the Java solution presented by ewernli.

edit: just saw, you insist on not using constructors but having init methods with different signatures instead. Why? This violates the Liskov substitution principle.

edit2: I suppose you have 2 options:

  1. Different names for your initializers (not the best of ideas, also since your subclasses will expose initializers, that only work partially (not good, see LSP mentioned above)).
  2. Live by the philosophy, that any class must be abstract or final. Example (assuming a space game):

An abstract base class, multiple concrete subclasses:

class ShipBase {//in Java you might wanna put the 'abstract' keyword just infront
 //... implementation of some sort
 //... maybe a protected intializer to call by subclasses
 //... no public initializer, since class is abstract
}
final class Fighter extends ShipBase {
 //... public initializer specific to Fighter
 //... other custom behaviour
}
final class Bomber extends ShipBase {
 //... I guess, this is obvious
}

now you may ask yourself: what if I want Fighter to be a base class (for, let's say, the EliteFighter2000), but also an instantiatable class. Simple. It just doesn't have to be.

class FighterBase extends ShipBase {
    //... implementation of whatever kind of things fighters have in common
    //... a protected intializer to call by subclasses    
}
final class Fighter extends FighterBase {
    //... public initializer possibly just forwarding to protected initializer
}
final class EliteFighter2000 extends FighterBase {
    //... here goes all the 'elite' stuff
}

This is also more flexible. You can now change the simple Fighter without affecting the EliteFighter2000, or you can decide you want to alter the common behaviour of all fighters by modifying FighterBase. Inheritance generally is a dangerous thing, and is often misunderstood and misused.
Sticking to this rule generally helps avoiding the subtle, yet often quite far-reaching coupling inheritance can introduce by lacking seperation of concerns. In this case, anything common to fighters is to be implemented in FighterBase and anything specific to simple Fighters goes right where it belongs.

greetz
back2dos

back2dos
So I can use object pooling - need to be able to reinitialize objects as if they were new.
Iain
@Iain: post updated
back2dos