Abstract classes have disjunctive semantics (logical OR) whereas interfaces have conjunctive semantics (logical AND).
The actual important thing that I wanted to capture is that an instance of Shape can only be one kind of shape at a time. With an interface a class could be more than one kind of Shape.
interface IFoo : IShape
{
//some stuff
}
public class SomeShape : IShape, IFoo
{
//I am a circle AND a square!
}Extension methods don't extend the type. They extend the functionality attached to the type.
F# has these too [1] (actually more powerful versions):
The thing about using sum-types (the original Shape example) is that they're not supposed to be extended. You're defining the range of the type, which allows for powerful inference of completeness when using them. If you need extensible classes then F# can do those too, it can represent interfaces, abstract classes and concrete classes [2][3][4], and can even generate ad-hoc classes from an interface by using Object Expressions [5].
I personally try to stick to the pure functional approach, but it can be very handy when interoperating with the .NET framework, or other C# based libraries.
[1] http://fsharpforfunandprofit.com/posts/type-extensions/
[2] http://fsharpforfunandprofit.com/posts/classes/
[3] http://fsharpforfunandprofit.com/posts/inheritance/
[4] http://fsharpforfunandprofit.com/posts/interfaces/
[5] http://fsharpforfunandprofit.com/posts/object-expressions/