public interface IShape
{
float Area { get; }
float Perimeter { get; }
}
public Circle : IShape
{
readonly float r ;
public Circle(float r)
{
this.r = r;
}
public float Area { get { return Math.PI * r * r; } }
public float Perimeter { get { return 2 * Math.PI * r; } }
}
public Square: IShape
{
readonly float a ;
public Square(float a)
{
this.r = r;
}
public float Area { get { return a * a; } }
public float Perimeter { get { return 4 * a; } }
}
Also, with this one you can create new Shapes in another project. With F# solution there, you must have access to original code.
I agree that it would be more idiomatic. I disagree that it is good.
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!
}
I actually think C# (and many OOP languages) gets around this fairly well, by having virtual and extension methods. Many types of functions can be added easily without needing to go back through every inheritor.
* EDIT - realised I responded with an answer not related to the topic; I'll leave this here as a point-of-reference for the OO side of F# *
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.