Overloading "=" and "<>" in F#

102 Views Asked by At
open System

type Point(X : float, Y : float) =
  class
    member public this.X : float = X
    member public this.Y : float = Y
    static member public Origin : Point = Point(0.0, 0.0)
  
    static member public (+) (P1 : Point, P2 : Point) : Point =
      Point(P1.X+P2.X, P1.Y+P2.Y)
    
    static member public (-) (P1 : Point, P2 : Point) : Point =
      Point(P1.X-P2.X, P1.Y-P2.Y)
    
    static member public op_Equality (P1 : Point, P2 : Point) : bool =
      P1.X = P2.X && P1.Y = P2.Y
      
    static member public op_Inequality (P1 : Point, P2 : Point) : bool =
        P1.X <> P2.X && P1.Y <> P2.Y
    
    override this.ToString() = 
      String.Format("({0}, {1})", X, Y)
  end

I was trying to overload "="(Equality operator) and "<>"(Inequality operator) but overloading equality and inequality operators by their symbols -"+"(Adition operator) and "-"(Subtraction operator) operators was overloaded by their symbols.- is not allowed.

I got this messages when I tried "="(Equality operator) and "<>"(Inequality operator) operators by their symbols:

The name '(=)' should not be used as a member name. To define equality semantics for a type, override the 'Object.Equals' member. If defining a static member for use from other CLI languages then use the name 'op_Equality' instead.

The name '(<>)' should not be used as a member name. To define equality semantics for a type, override the 'Object.Equals' member. If defining a static member for use from other CLI languages then use the name 'op_Inquality' instead.

I followed the second advice to define the operators as static members. If we look at the bright side, There is no error. But, on condition that p1 = Point(1, 0) and p2 = Point(1, 0) p1 = p2 must return true(In my program it returns false) and p1 <> p2 must return false(In my program it returns true)

I'm new at F#. I don't know how to correct this bug. Could someone help me?

1

There are 1 best solutions below

0
Brian Berns On

There's rarely any need to implement your own structural equality in F#. If you define Point as a record type instead, it will implement structural equality by default:

type Point =
    {
        X : float
        Y : float
    }

    static member public (+) (P1 : Point, P2 : Point) =
        { X = P1.X + P2.X; Y = P1.Y + P2.Y }
    
    static member public (-) (P1 : Point, P2 : Point) : Point =
        { X = P1.X - P2.X; Y = P1.Y - P2.Y }

Test code:

let p1 = { X = 1.0; Y = 0.0 }
let p2 = { X = 1.0; Y = 0.0 }
(p1 = p2) |> printfn "%A"    // true
(p1 <> p2) |> printfn "%A"   // false

You also get pretty printing for free with record types, so you usually don't have to override ToString:

(p1 + p2) |> printfn "%A"   // {X = 2; Y = 0}

If you decompile the Point record type into C#, you can see how structural equality is automatically implemented by the F# compiler:

public sealed class Point : IEquatable<Point>, IStructuralEquatable, IComparable<Point>, IComparable, IStructuralComparable
{
    ...
}

Related Questions in F#