I'm not an absolutist on any of this either, and in practice I make classes inherit each other when it's convenient and makes my code work well. And it sounds like we agree that using mixins is a powerful way of avoiding the ontology traps that lurk in class inheritance structures, and that not having them is painful and limiting [1]. So I'm not even sure there's a real disagreement here.
[1] I too used mixins in C#. Not sure how you'd do it now, but at the time you had to use Castle DynamicProxy and it was...unpleasant. But worth it.
In C#, you define an interface, and in the same namespace as the interface, you define a set of extension methods to the interface. Any class that implements the interface gets the extension methods. The interface can even be empty.
namespace Yarp{
public interface IMixinFoo{
}
public static class IMixinFooExt{
public static void DoBar(this IMixinFoo _this){
Console.WriteLine("poo");
}
}
}
namespace Grog{
using Yarp;
class Baz : IMixinFoo{
public static void Main(string[] args){
Grog g = new Grog();
g.DoBar();
g = null;
g.DoBar(); // still works, if DoBar guards against a null-ref exception
}
}
}
I find myself not using extension methods so much these days unless I want behavior for a specific instance of a generic type. The problem is state and polymorphism, which can be handled well enough via delegation to a nested mixin object + an interface to tag objects that have this nested mixin object.
With C# borrowing "everything must live in a class" from Java, extension methods are the only way to do sane functional programming in C#. That, LINQ is developed entirely through extremely generic extension methods. Indeed, extension methods were added to C# to enable LINQ, which was created to drag .NET developers over to FP.
Extension methods are great for writing anything that chains a lot of method calls together, specifically because they aren't methods on the object. Because it's possible to call an extension method on a null instance, you don't have to inject arbitrary error handling in the middle of your call chain. You can do it at the function site.
That said, there are a number of places where LINQ doesn't chain very well. It's built-in aggregating functions, for one. Average, Sum, Min, etc., don't know how to handle a 0-sized collection. And of course, those functions are notionally not defined for 0-sized collections. But I think a better design is to allow the user to specify a default value in the case of a 0-sized collection, or to just return null (signifying "there is no Average, there is no Sum"), rather than throw an exception. So I have a polyfil of sorts to make similar extensions that play nicer.
The problem is the types. Those methods do know how to handle 0-sized collections, but they must be operating on nullable types.
Enumerable.Empty<int?>().Average() returns null.
If you have a sequence of integers, you can get the behavior you want by converting the elements to nullable types like this. seq.Average(x => (int?)(x))
Ah, yeah, I'd forgotten about extension methods and how they could be used as mixins. I did indeed switch to that when C# 3 came out. I guess I was just remembering earlier pain.
It's not a crime, but Allman bracing is normally used. Every official guidelines, every programming book, every open source project I know of, uses Allman for C#, so anything else stands out like a sore thumb. It's about convention, consistency and resulting readability. I'm not a fanboy of bracing style :) I think that in Rome you should do as Romans do. When I use Java or PHP, I use K&R - it's a context thing, it would just look weird and out of place otherwise. I believe it's better to embrace the "native" (common) coding style in each language, unless you only ever work on your own.
Allman bracing sucks on wide screen laptops, and it was only when I found the 3-font point brace line Visual Studio extension that I was able to switch. I'm really getting annoyed with braces, we should get rid of them.
Python replaced them with indentation. Funnily enough it is one of the most complained about things with Python. I hated it at first, and its still a pain when switching between JavaScript and Python, but you never get the mismatched brace problem which more than makes up for the problems.
Fair enough. I just compose my mixins directly and bridge the gap through delegation. I wish these rants included the obvious solutions, I'm really tired of the argument of OOP sucks because...Java. Or OOP sucks because...single inheritance. There are plenty of things we can do to make our languages not suck, and this is not a fundamental limitation of OOP.
[1] I too used mixins in C#. Not sure how you'd do it now, but at the time you had to use Castle DynamicProxy and it was...unpleasant. But worth it.