API's that Suck

June 8, 2009

F#- You can overload operators, but you can’t use them.

Filed under: Uncategorized — Grauenwolf @ 10:58 pm

According to the documentation, F# supports operator overloads. This means you should be able to overload common operators like > and <.

YOU CAN OVERLOAD OPERATORS,

F# actually does does support declaring operator overloads. If you compile the code below it will emit the same IL you would expect from other .NET languages.

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

BUT YOU CAN’T USE THEM!

That’s right folks. Even though F# goes out of its way to allow you to overload operators in such a way that other languages can honor them, F# itself doesn’t.

Well, that’s a bit of an exaggeration. Lets look at them each in turn:

  • + (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.

WHAT THE HELL JUST HAPPENED?

Ok, so you can’t overload op_Concatenate. Fine, I get that. It’s stupid, but whatever.

But what the hell is going on with op_GreaterThan? I can overload the operator just like op_Addition, but it doesn’t honor it. Moreover, it waits until runtime to tell me that it is going to ignore the overload and use System.IComparable instead.

Seriously, is this what they mean by a “strongly typed language”? You can’t make safe conversions like integer to decimal or string to Option<string>, but you can do something reckless like cast a class to an interface it doesn’t implement?

STATIC TYPING MY ASS

I have never seen another language screw up static typing so badly. Support for operator overloads is hard to design, I get that. But to get them so wrong that they effective break your static type checker is inexcusable.

Advertisements

7 Comments »

  1. > But what the hell is going on…

    Have you asked in a forum where there’s a chance someone might actually know – like hubFS?

    http://cs.hubfs.net/forums/

    Comment by Isaac Gouy — June 8, 2009 @ 11:08 pm

    • I should, but honestly I’m so pissed off about it that I need some time to cool down.

      Comment by grauenwolf — June 8, 2009 @ 11:37 pm

  2. Note that this code gives compiler warnings like:

    The name ‘(>)’ should not be used as a member name. To define comparison semantics for a type, implement the ‘System.IComparable’ interface. If defining a static member for use from other .NET languages then use the name ‘op_GreaterThan’ instead.

    The name ‘() and (<), which themselves use IComparable.

    Comment by Brian — June 9, 2009 @ 4:53 pm

    • Oops, in my previous comment, my less-than and greater-than operators got munged into markup. I intend to say that

      F# supports generic structured comparison, allowing you to compare tuples, lists, arrays and other data structurally using the default implementations of the less-than and greater-than operators, which themselves use IComparable.

      Comment by Brian — June 9, 2009 @ 4:57 pm

    • Yes, I understand how it works. My objections are in regards to why it works that way.

      Comment by grauenwolf — June 9, 2009 @ 10:47 pm

  3. Any F# book will explain this stuff. , =, , compare are not your usual .NET operators in F#. They are structural and generic.

    Your code gives 2 very clear warnings (which you neglect to mention!). They indicate that your comparison operators are not used from F# and even tell you how to define comparison semantics for F# that will actually _work_ with F# structural comparison. Would you rather F# just silently let you define operators that _didn’t_ work with F# structural comparison?

    Its possible you just have something against structural comparison altogether? There are pros and cons each way but structural comparison is pretty normal in functional languages.

    For example, the compiler has explained to you how to make your type work with tuple comparison in F#, e.g. take this

    (1,2) < (3,4)

    and then replace with your own values.

    Agreed F# and OCaml's generic comparison operators have weaker types than you might wish, and are a potential failure point, but nowhere near as weakly typed as .NET's and Java's .Equals(object) method. There are shades of grey here: Haskell has very nice strong typing for structural types, F# and OCaml are in the middle, C# overloads are nice but non-structural, and .NET and Java OO tend to be weak.

    Comment by Jamey — June 9, 2009 @ 11:31 pm

  4. […] F# – You can overload operators, but you can’t use them. […]

    Pingback by Rick Minerich's Development Wonderland : Discoveries This Week 06/14/2009 — June 15, 2009 @ 12:19 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: