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.
The short answer: An abstract class allows you to create functionality that subclasses can implement or override. An interface only allows you to define functionality, not implement it. And whereas a class can extend only one abstract class, it can take advantage of multiple interfaces.
Mixins are sometimes described as being "included" rather than "inherited". In short, the key difference from an inheritance is that mix-ins does NOT need to have a "is-a" relationship like in inheritance. From the implementation point of view, you can think it as an interface with implementations.
Mixins is not a way to get multiple inheritance in the classical sense. Mixins is a way to abstract and reuse a family of operations and state. It is similar to the reuse you get from extending a class, but it is compatible with single-inheritance because it is linear.
Mixins encourage code reuse and can be used to avoid the inheritance ambiguity that multiple inheritance can cause (the "diamond problem"), or to work around lack of support for multiple inheritance in a language. A mixin can also be viewed as an interface with implemented methods.
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.
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).
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()); } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With