Abstract classes vs. interfaces vs. mixins
Could someone please explain to me the differences between abstract classes, interfaces, and mixins? I've used each before in my code but I don't know the technical differences.
Abstract Class
An abstract class is a class that is not designed to be instantiated. Abstract classes can have no implementation, some implementation, or all implementation. Abstract classes are designed to allow its subclasses share a common (default) implementation. A (pseudocoded) example of an abstract class would be something like this
abstract class Shape {
def abstract area(); // abstract (unimplemented method)
def outline_width() = { return 1; } // default implementation
}
A subclass might look like
class Rectangle extends Shape {
int height = width = 5;
def override area() = { return height * width; } // implements abstract method
// no need to override outline_width(), but may do so if needed
}
Possible usage
def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}
If a subclass does not override unimplemented methods, it is also an abstract class.
Interface
In general computer science terms, an interface is the parts of a program exposed to a client. Public classes and members are examples of interfaces.
Java and C# have a special interface
keyword. These are more or less an abstract class with no implementation. (There's trickiness about constants, nested classes, explicit implementation, and access modifiers that I'm not going to get into.) Though the part about "no implementation" doesn't fit any more in Java, they added default methods. The interface
keyword can be seen as a reification of the interface concept.
Going back to the Shape example
interface Shape {
def area(); // implicitly abstract so no need for abstract keyword
def outline_width(); // cannot implement any methods
}
class Rectangle implements Shape {
int height = width = 5;
def override area() = { return height * width; }
def override outline_width() = { return 1; } // every method in interface must be implemented
}
def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}
Java and C# do not allow multiple inheritance of classes with implementation, but they do allow multiple interface implementation. Java and C# use interfaces as a workaround to the Deadly Diamond of Death Problem found in languages that allow multiple inheritance (which isn't really that deadly, if properly handled).
Mixin
A mixin (sometimes called a trait) allows multiple inheritance of abstract classes. Mixins don't have the scary association that multiple inheritance has (due to C++ craziness), so people are more comfortable using them. They have the same exact Deadly Diamond of Death Problem, but languages that support them have more elegant ways of mitigating it than C++ has, so they're perceived as better.
Mixins are hailed as interfaces with behavioral reuse, more flexible interfaces, and more powerful interfaces. You will notice all these have the term interface
in them, referring to the Java and C# keyword. Mixins are not interfaces. They are multiple inheritance. With a prettier name.
This is not to say that mixins are bad. Multiple inheritance isn't bad. The way C++ resolves multiple inheritance is what everyone gets all worked up about.
On to the tired, old Shape example
mixin Shape {
def abstract area();
def outline_width() = { return 1; }
}
class Rectangle with Shape {
int height = width = 5;
def override area() = { return height * width; }
}
def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}
You will notice there is no difference between this and the abstract class example.
One extra tidbit is that C# has supported mixins since version 3.0. You can do it with extension methods on interfaces. Here's the Shape example with real(!) C# code mixin style
interface Shape
{
int Area();
}
static class ShapeExtensions
{
public static int OutlineWidth(this Shape s)
{
return 1;
}
}
class Rectangle : Shape
{
int height = 5;
int width = 5;
public int Area()
{
return height * width;
}
}
class Program
{
static void Main()
{
Shape[] shapes = new Shape[]{ new Rectangle(), new Oval() };
foreach (var s in shapes)
{
Console.Write("area: " + s.Area() + ", outline width: " + s.OutlineWidth());
}
}
}
In general:
An interface is a contract specifying operations, but without any implementation. Some languages (Java, C#) have baked-in support for interfaces, and in others 'interface' describes a convention like a pure virtual class in C++.
An abstract class is a class which specifies at least one operation without an implementation. Abstract classes can also provide some parts of their implementation. Again, some languages have baked-in support for marking classes as abstract and it is implicit in others. For example, in C++ a class which defines a pure virtual method is abstract.
A mixin is a class which is designed to make implementation of certain functionality easier in subclasses, but which is not designed to be used by itself. For example, say that we have an interface for an object that handles requests
interface RequestHandler {
void handleRequest(Request request);
}
Perhaps it would be useful to buffer the requests by accumulating them until we have some predetermined number and then flushing the buffer. We can implement the buffering functionality with a mixin without specifying the flush behavior:
abstract class BufferedRequestHandlerMixin implements RequestHandler {
List<Request> buffer = new List<Request>();
void handleRequest(Request request) {
buffer.add(request);
if (buffer.size == BUFFER_FLUSH_SIZE) {
flushBuffer(buffer);
buffer.clear();
}
}
abstract void flushBuffer(List<Request> buffer);
}
This way, it's easy for us to write a request handler that writes requests to disk, calls a web service, etc. without rewriting the buffering functionality each time. These request handlers can simply extend BufferedRequestHandlerMixin
and implement flushBuffer
.
Another good example of a mixin is one of the many support classes in Spring, viz. HibernateDaoSupport.
Reference to Java and given example of Abstract class to provide mixin is misleading. First of all, Java does not support "mixins" by default. In Java terms abstract class and Mixins become confusing.
A mixin is a type that a class can implement in addition to its "primary type" to indicate that it provides some optional behavior. To speak in Java terms, one example would be your business value object implementing Serializable.
Josh Bloch says - "Abstract classes can not be used to define mixins - since a class can not have more than one parent" ( Remember Java allows only one "extends" candidate)
Look for languages like Scala and Ruby for appropriate implementation of the notion of "mixin"