Thursday, May 12, 2005

Interfaces and Abstract Classes Further Differentiated

As promised yesterday, I converted the Java code from the book to C#, just to see what I would have to change. There were very few changes, really, but they each taught me a little something.

In Java when you want to inherit from a base class, you use the keyword "extends," as in public class MallardDuck extends Duck . When you want to implement an interface, the keyword is a bit more obvious: public class Squeak implements QuackBehavior . C# replaces both words with a colon:
public class MallardDuck : Duck
public class Squeak : IQuackBehavior

The convention of starting the name of an interface with a capital 'I' does not exist in Java. Perhaps the indistinguishable derivation syntax made that a useful practice.

In Java the methods in the interface are explicitly made public:
public interface QuackBehavior {
    public void quack();
}

In C# all members of an interface are implicitly public. In fact they are explicitly implicitly public. That is, access modifiers are not allowed at all on interface members, including the public modifier. So it looks like this:
public interface IQuackBehavior {
    void quack();
}

It really doesn't make sense for members of an interface to be anything but public. Look up "interface" in Microsoft's C# Programmer's Reference and you will immediately learn that "An interface defines a contract." The point of a class claiming to implement an interface is that other functions then know that they can count on that class to have the methods and properties specified by the interface. Limiting access to the methods you contract to implement doesn't follow. Thus the given public status of all the members of an interface.

The next change I had to make from Java to C# was in regards to the reference variables for the behavior interfaces declared in the Duck abstract class.
public abstract class Duck {
    IFlyBehavior flyBehavior;
    IQuackBehavior quackBehavior;
    ...
}

Notice that there are no access modifiers on these variables. This did not cause an error until I tried to make a real duck:
public class MallardDuck : Duck {
    public MallardDuck() {
        quackBehavior = new Quack();
        flyBehavior = new FlyWithWings();
    }
    ...
}

The compiler failed because quackBehavior was undefined in the context of the MallardDuck constructor. It appears that default access for variables is private. The "private" modifier makes a member accessible only to the class itself, not to any outside classes or even derived classes. Since the final version of the Duck abstract class includes an accessor method ( public void setQuackBehavior(QuackBehavior qb) {quackBehavior = qb; } ), I chose to make the reference variables protected. "Protected" is different from "private" only in that derived classes are allowed access.

The final change I had to make to the code was to add override to the modifiers for the implementation of the abstract method display(). I don't have a good theory as to why C# requires this keyword while Java just figures out that the method in the base class was abstract and runs with it.

So what can I say now about the differences between an interface and an abstract class?

An interface is a contract specifying that any class that implements it will provide implementation code for the specified members with the specified parameters and return values. All implementation of an interface is the responsibility of the class that implements it, there is no code allowed in the interface itself. All the members of an interface are necessarily public. A class may implement multiple interfaces: it only needs to provide all the members specified by each of them.

An abstract class is a class that may not be instantiated as is. It must have a derived or inherited class to get an instance. We can always give more specific information about a real dog that we have in front of us than we can about dogs in general. My niece's dog, Jack, is an instance of the Jack Russell Terrier class which is derived from the abstract Terrier class. I could correctly say that Jack is a terrier (or a dog, a mammal, an animal, a discrete hunk of matter). But if I asked you to make a terrier named Jack (assuming you had such abilities), I have not given you enough specifics to get the kind of dog I'm really looking for. As regards crossbreeds, they pretty much have to be considered a new breed (class). They have attributes that contradict what it means to be either of the former breeds. All this discussion of dogs has a purpose. The point is that a class may only extend one base class. Now that class in turn may certainly have a whole series of base classes in it's lineage (JackRussellTerrier extends Dog, Dog extends Mammal, Mammal extends Animal, Animal extends Matter), but never more than one at once. An abstract class really is a class though, and it's members may have code and a variety of access modifiers.

Posted to Work Life at May 12, 2005 9:35 PM
Comments

Reading today's blog entry is very much like what I have been doing all morning, namely editing a heavily scientific document and trying to explain in layman's terms signal transduction pathways, inducible nitric oxide synthase, cytokine production, growth factor induced proteins, and transcription. And I have to talk my reader into funding this. English! I want English!
Mom

Posted by: Susan McJilton at May 13, 2005 12:19 PM