11

From Why is OCaml's (+) not polymorphic?, Keith said:

The + versus +. thing removes a lot of subtle bugs which can crop up in converting different sizes of integers, floats, and other numeric types back and forth. It also means that the compiler always knows exactly which numeric type is in use, thus making it easier to recognize when the programmer has made incorrect assumptions about a number always having an integer value. Requiring explicit casting between numeric types may seem awkward, but in the long run, it probably saves you more time tracking down weird bugs than you have to spend to write that extra period to be explicit.

ygrek also said:

you start to count for all other compromises that F# had to do in order to support this overloading.

Could someone please explain what were "a lot of subtle bugs" which existed in OCaml and what are "all compromises" which F# has to do beside inventing workaround statically resolved type?

Community
  • 1
  • 1
MiP
  • 5,846
  • 3
  • 26
  • 41
  • 8
    Well, if you had a function that was using `+ 1` to do array indexing, and you passed it the float `2.5`, you could get some unexpected behavior. That could be one of the "weird bugs" that Keith Irwin was talking about. However, F#'s overloaded `+` operator does not allow you to add different types -- you can't add an `int` to a `float`, and you can't even add a signed int to an unsigned int -- so it still manages to avoid the entire category of "weird bugs" when you pass the wrong numeric type to your function, while still maintaining convenience. – rmunn May 14 '17 at 11:32
  • 8
    Also, the "lot of subtle bugs" that was mentioned was *not* in OCaml, but in languages like C that would automatically convert ints to floats when they were used in mixed-number-type expressions. That would result in mistakes like http://stackoverflow.com/q/13530209/2314532, where someone expected `(50 / 100) * 100.0` to equal `0.5`, but it in fact equaled `0.0` because of the rules of integer division. That's the kind of "weird bug" that both OCaml and F# protect you from. – rmunn May 14 '17 at 11:34
  • @rmunn But it's not a subtle bug, it's a feature. – MiP May 15 '17 at 08:26
  • 6
    Which part is the "it" in your "it's a feature" sentence? The automatic casting of `int` to `float` in C? It's a feature in the sense that it was deliberately put into the language, but it's *also* a subtle bug because it subverts programmer expectations -- you have int context and float context going on at the same time in that question, which is not what the programmer expected. So I'd argue that it's a **mis**feature, and that F# gets it right when it requires you to *explicitly* cast `int` to `float`, or vice-versa. – rmunn May 15 '17 at 09:25

1 Answers1

7

Could someone please explain what were "a lot of subtle bugs" which existed in OCaml

The bugs didn't exist in OCaml. They existed in languages like C and were fixed in OCaml by distinguishing between different numerical types. However, as Keith later alludes to, the problem wasn't overloaded arithmetic operators but so-called "promotion". You can get rid of promotion and still have overloaded arithmetic operators (F# does this and it works really well).

and what are "all compromises" which F# has to do beside inventing workaround statically resolved type?

The two extremes are no overloading like OCaml or full overloading like type classes in Haskell. Both extremes have disadvantages. F# chose a middle ground where some operators and functions can be overloaded but others cannot and all overloads must be resolved at compile time. This is more complicated than either the OCaml or the Haskell solutions but it is a pragmatic trade-off: you get simple code that is predictably fast. However, type inference is more complicated (you must specify types some times), code no longer composes (cutting and pasting code around can cause different types to be inferred, breaking the code) and you need to remember what can be overloaded and what cannot.

J D
  • 48,105
  • 13
  • 171
  • 274