views:

407

answers:

2

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
+4  A: 

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

Brian
Ok, then why doesn't this work? "static member (>) (left : OppTest4, right : OppTest4) = left.value > right.value"
Jonathan Allen
> it's hard to imagine any generally interoperable operator stuff across all languages on .Net today. < But there is! If you use the code I show in my question, VB will honor all the operators. F# is emitting the standard IL code, it just isn't consuming it.
Jonathan Allen
I'd be curious on whether I can shadow the default operator definition only for one type using a let binding - I don't have control over the type implementation. If so how would that be done?I've tried let (>) (a:SomeType) (b:SomeType) = ... but then any comparison made between other types broke so that 2 > 1 didn't compile anymore.
emaster70
@emaster, no you can't shadow just for one type. All, if I can find a few hours to set aside over the next week, I'll try to blog about this, as there are a lot of different interacting forces at work.
Brian
In the meantime, someone else has posted a nice summary at http://cs.hubfs.net/forums/thread/10860.aspx
Brian
A: 

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 [email protected].

vpolozov
The runtime error is not a bug, it is By Design. I have not seen a public discussion of this design, however, which is well-motivated even if non-obvious, so I'll try to rectify that soon.
Brian
Ok, it is impossible to proof, that every instance of OppTest4 doesn't have IComparable interface.But still it is known that there are OppTest4 instances that can't be cast to IComparable ! So there must be a warning at least! Why not?
vpolozov
@.vpolozov.name: it looks like section 9.6 of the F# spec (http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec2.aspx) indicates that they're considering adding warnings in certain situations where use of the comparison operators is likely to fail.
kvb