F# and Operator Overloads: (>) and (^)

2019-02-19 02:47发布

问题:

Ok, so can someone explain to me why F# allows you to overload the > and ^ operators, but doesn't allow you to use them?

+ (op_Addition): Works just fine.
^ (op_Concatenate): Compiler error in F#. Apparently only strings can be concatenated.
> (op_GreaterThan): Runtime Error – Failure during generic comparison: the type Program+OppTest4 does not implement the System.IComparable interface.

If I compile my F# code as a library and use those operators from VB, they all work. If I use those operators from C#, all but op_Concatenate work (as expected). But F# not only ignores some them, the static type checker doesn't even bother telling you that it plans on doing so.

Edit Code Sample

type OppTest4(value: int) =
   member this.value = value
   static member (^) (left : OppTest4, right : OppTest4) =
     OppTest4( Int32.Parse( left.value.ToString() ^ right.value.ToString()  ))
   static member (+) (left : OppTest4, right : OppTest4) =
     OppTest4(left.value + right.value )
   static member (>) (left : OppTest4, right : OppTest4) =
     left.value > right.value
   static member (<) (left : OppTest4, right : OppTest4) =
     left.value < right.value

回答1:

F# has default meanings for these operator symbols that's reasonable for F#. You can always define your own meanings that shadow the defaults, a la

let (>) x y = ...

For example, you could define this operator to mean "T.operator>(U)" (assuming x has type T and y has type U).

See prim-types.fs in FSharp.Core in the source distribution for the default definitions. (They are non-trivial!)

Given the combination of (1) lack of support for a type-class like mechanism on the CLR (for defining common semantics among a set of otherwise-unrelated types) and (2) the fact that primitive types (like 'int') often need to be special-cased for any programming language implementation (e.g. System.Int32 does not define an operator+ method, but most programming languages choose to behave as though such a method exists), it's hard to imagine any generally interoperable operator stuff across all languages on .Net today. There are a lot of design-trade-offs depending on exactly what a language chooses to do (too many interacting issues to sum up here). In any case, you should be able to call any method from F#, and if the default operator behaviors are undesirable, you can redefine (shadow) the operators to the behaviors you want. If there's a particular scenario you have in mind that you're having trouble to make work, let me know.

EDIT

I added more detail at

http://cs.hubfs.net/forums/thread/10869.aspx



回答2:

I agree, there is inconsistency: operator can be defined, but can't be used.

Are you asking, why F# designers decided to implement comparison with System.IComparable interface rather than operators overload? I don't know why, but in OO language I would prefer IComparable rather than operators overloading. So, I would suggest to F# developers to break C# compatibility and forbid "static member (>) (...)" syntax sugar.

If you are asking how to call these overloaded operators it is pretty easy: use op_Concatenate, op_GreaterThan or op_LessThan static members. (Really, I've got a compiler warning, describing the problem. F# 1.9.6.16)

Runtime Error casting to System.IComparable without any compiler warning definitely is a bug. You can send it to fsbugs@microsoft.com.