Interfaces—at least in C#/Java—are equivalent to product types; they let you express the notion of conjunction within the type system.
Similarly, “implementation inheritance” (where every class is either sealed/final or abstract) is how we express sum types.
We can simulate type classes in C# by using implicit casts to abstract classes (interestingly, it’s not so straightforward to simulate the awesomeness of type classes in F#).
The key to all of this is to realize that “types” and “classes” are not equivalent, even though C# and Java conflate them.
Similarly, “implementation inheritance” (where every class is either sealed/final or abstract) is how we express sum types.
We can simulate type classes in C# by using implicit casts to abstract classes (interestingly, it’s not so straightforward to simulate the awesomeness of type classes in F#).
The key to all of this is to realize that “types” and “classes” are not equivalent, even though C# and Java conflate them.