5 ms·
As someone who keeps hearing about F# but has not used it, I look at C#'s evolution - generally speaking, the language just keeps getting more and more terse fo
by thr0waway1239 10y ago
As someone who keeps hearing about F# but has not used it, I look at C#'s evolution - generally speaking, the language just keeps getting more and more terse for the common use cases (without sacrificing readability), especially in line of business applications. Combine it with a tool like Resharper, and generally, coding in C# is quite a pleasure.
Also, it is not as if C# is stagnant - e.g. the introduction of async and await keywords.
It seems as if people promoting F# try to create use cases which are, frankly, not very often seen in the domains where C# is commonly used. Maybe I am completely mistaken, but F# seems to lack a so called "killer app" use case where people notice and say "aha! That's why you need it".
- dgudkov 10y agoAs someone who writes in C# and F# I can say the absence of nulls in F# alone makes it worth switching. Typically if something compiles in F# then it works reliably - a huge time/money saver.
- thr0waway1239 10y agoNot disagreeing - can you explain a scenario where this helped so we can all understand how it is better than dealing with nulls in C#?
- DontGiveTwoFlux 10y agoI'm working on a big c# app right now. All over the code base are areas where we always assumed a call to .first() would always return at least one thing. The business needs have changed and now we have use cases where we return nothing. I've been playing a game of hunting down the many little areas where this could crop up. I can imagine that in f# this refactor would be a lot simpler and would allow me to have a case of empty that I could propagate around and handle transparently.
- sickbeard 10y agoHow would functional programming help you in this department?
- piaste 10y agoIn C#, null is just one possible value of the regular type Foo. The compiler cannot tell whether you have started returning null where you previously only returned non-null values, nor can it tell whether you've handled those null values correctly at the consumption site. In F#, None is a subtype of the Option<Foo> union type, which is different from the plain Foo type and from the other subtype Some Foo. If you change a function that used to return a plain Foo into one returning Option<Foo>, every place in your code where that function is consumed will throw a compile error until you edit it to unwrap and handle the distinct Some Foo and None subtypes.
- actsasbuffoon 10y agoMany functional programming languages have stronger type systems than C#. They typically don't accept null as a valid substitute for any type. To represent a nullable type, you wrap the value in a generic container. Think of it as being like an array that contains at most 1 item. The interface of this generic container only allows you to interact with the (potentially) wrapped value in a way that is type safe. That doesn't completely eliminate having to think about how the business logic should differ for missing values, but it ensures that you'll never get a null pointer exception.
- dgudkov 10y agoThere is no way (from a type perspective) to guarantee in C# that an instance of a class can never be null -- this has to be ensured by code logic, conventions, etc. As application gets bigger it becomes easy to overlook a case that leads to a null reference exception. The type system in F# can guarantee that an instance of a class can never be null and you can always refer to it safely.
- marxama 10y agoI've mentioned this before, but it's worth mentioning again: unfortunately, F# is not guaranteed to be null-less. As soon as you are working with instances of some class (for example string), you are back to normal null checking. Of course you can wrap the string in an option, but it can still have a value which is null... So even if you don't have any kind of interop, you can still end up with NREs. So what you'll have to do is tell your teammates to not use nulls, and instead make proper use of option etc, and then you're back to avoiding NREs by conventions, not by the compiler helping you out. Am I incorrect in this? F# seems like a very nice language, but honestly, C# is getting so much love from Microsoft that I haven't felt motivated to learn F# properly (the situation is very different in Java land). Seems like non-nullable references may even make it into C#, so there you go! :)
- piaste 10y ago> So what you'll have to do is tell your teammates to not use nulls, and instead make proper use of option etc, and then you're back to avoiding NREs by conventions, not by the compiler helping you out. Am I incorrect in this? You're not wrong, but I think you're being too rigid. Type safety isn't a yes or no, it's a sliding scale between mathematically-guaranteed correctness at compile time and unsafe user convention, and on that scale F# is definitely to the left of C# - although it's to the right of Haskell and dependently-typed langs - because while it doesn't provide full safety, it still make safe code easier to write (the famous "pit of success"). Sure, F# lets you write "null" instead of "None" if you want. But C# lets you write, e.g., "dynamic" - does that mean C# lacks static typing and "avoids MissingMemberExceptions by convention"? Of course not; you have to go out of your way to use dynamic, because the language provides you with static types and encourages you to use them. Likewise, F# provides you with the Option type and encourages you to use it - you have to go out of your way to use null in its stead. A F# coworker that used null would be committing an obvious code review faux pas, much like a C# coworker that insisted on using dynamic duck typing instead of interfaces. (Whereas "null" is generally not considered a code smell in C#... and note that it's entirely possible and not at all difficult to implement a safe Option type in C#! It's just neither idiomatic nor popular.) Another example is casting. In weaker languages, casting is implicit and dangerously uncontrollable. C# does better: you must explicitly cast types, but it's up to you to make sure it's a safe cast. And F# goes a tiny bit further: you have separate operators for safe upcasts and unsafe downcasts, and using the former on an unsafe cast won't compile. It's not 100% safety, but it's still better.