Hacker News new | ask | show | jobs
by wyoung2 3247 days ago
Just to add to what the others have said:

1. Immutable values by default avoids whole categories of problems. Just for one example, you can't have a data race between two threads if all the public values accessible from each thread are guaranteed immutable.

2. F# forces all cases to be handled. You've doubtless run into C# code that has a switch statement that doesn't have cases for all possible inputs, and no default case. F# doesn't have a direct equivalent of "switch" at all, but it does enforce completeness in the equivalents it does have. For example, it's illegal in F# to say something like "if foo > 1 then ... elif foo < 1 ..." since that leaves the 0 case unhandled. This is not just about better compiler warnings: it's required by the very fact that "if/else" is an expression, not a statement, so all branches must produce a value for all inputs.

3. F# has units of measure data types. Ever had an application bug because you've incorrectly passed a bare "int" value holding milliseconds to a function expecting seconds? I have. F# lets you define your units as part of the data type, so that it's a compiler error to pass milliseconds to a function expecting seconds.

I could go on, but as you can see, there really are substantial differences in practice between F# and C# code.