views:

187

answers:

3

I've recently tried to write something in F# making use of Microsoft Solver Foundation Services and while doing so I bumped into an issue: I had to express a (Term > Term) condition which in C# could simply be expressed as t1 > t2 and returns another Term object. In F#, instead, I had to call Term.op_GreaterThan in order to achieve the same result as using t1 > t2 would yield a bool and not a term.
Now I'm wondering why is F# only picking op_GreaterThan if it yields a boolean? And what meaning would F#'s interpretation of t1 > t2 have while Term doesn't implement IComparable?
Please mind that I understand why doing such a thing with equality and the whole equality based on structural comparison notion, I just don't get how that could be extended to "greater than"/"smaller than" comparisons.

+2  A: 

Intuitively, a comparison operator like > should always yield a boolean value!

You can answer the question a > b with yes or no, but not with 3 or new Stopwatch().

When it could return anything else, something like

if a < b then

would make no sense any more.

F#-objects (tuples, lists etc) often implement IComparable or IStructuralComparable which can for example sort a tuple lexicographically.

*Note:

IMHO, it's not the best solution to be allowed to compare any objects and then throw exceptions at runtime. Haskell has solved this better using typeclasses.

greater :: (Ord a) => a -> a -> Bool
greater a b = a < b

Comparing uncomparable types would fail at compile-time.

Dario
I get the fact that from a language standpoint it makes sense to have a > b yield a boolean, but .NET allows op_GreaterThan to be defined as ('a * 'b) -> 'c so wouldn't the sake of interop suggest that decent compatibility in those cases should be present? (especially since the case I'm considering is a Microsoft library...)
emaster70
+4  A: 

Textbook Answer:

Operator overloading is not part of the Common Language Specification, meaning compiler writers are free to ignore or only partially support it if they feel like. As a library writer, you are responsible for providing alternate means for people to work with the class.

Pragmatic Answer:

Because it is a stupid thing to do in the first place. The op_GreaterThan method was explicitly created to make comparisons. That it, you aren't supposed to do 'interesting' things with it like concatinating two terms. The CLR only lets you abuse it because it needs to support legacy languages like C++.

By the way, there is an overload specifically for joining two things together. It is called op_Concatenate. You really should consider using it instead of op_GreaterThan.

EDIT

Almost Good Answer:

In F# the concatination operator I mentioned is ^.

I call this the almost-good answer because I'm not so sure that C# supports it. I think it is only allowed in VB and F#.

EDIT #2

It seems F# isn't honoring the ^ overload after all.

EDIT #3

WTF is going on here? F# doesn't honor the > operator at all. Sure you can overload it, and it will emit the op_GreaterThan method correctly, but it ignores it. It doesn't even try to use op_GreaterThan, instead it looks for the System.IComparable interface.

Even worse, this is a runtime check. Even though it can statically determine that class Foo doesn't implement IComparable, it still goes ahead and compiles the code anyways.

Jonathan Allen
And of course, if nothing else you could define your own F# operator that calls Term.op_GreaterThan explicitly.
Joel Mueller
I'm not really doing any concatenation, but your answer pretty much clears up the design choice. I still don't get the meaning of Term > Term when there's really no way the F# compiler could give it a reasonable meaning without using op_GreaterThan, but at least I get the language design choice
emaster70
@Joel, Can you? From my research you can overload > in F#, but you can't consume it. It just iqnores the overload and looks for IComparable instead.
Jonathan Allen
@Emaster70. The language is just plain broken.
Jonathan Allen
Grauenwolf, I don't know if you can make the greater-than symbol do what you want, but you can invent your own combination of symbols and make that do what you want. Something like... let (|+) (x:Term) (y:Term) = x.op_GreaterThan(y)
Joel Mueller
I've found a workaround to my issue: I can just shadow the (>) operator, perform a type test and if the type is not one for which I want to customize behavior, I can just call Operators.(>). This appears to be working fine.
emaster70
A: 

You don't have to use the < and > operators. The Solver Foundation Services Model class has Greater and Less methods, you should be able to use those instead.