3 ms·
Because if you are a top-notch C# dev, F# is just like you normally code but with less brackets and null reference exceptions. Also, you haven't experienced im
by AdeptusAquinas 8y ago
Because if you are a top-notch C# dev, F# is just like you normally code but with less brackets and null reference exceptions.
Also, you haven't experienced implicit typing until you have used F#'s ridiculously powerful approach to it (relative to C# anyway).
- bunderbunder 8y agoI'd argue that that's painting with too broad a brush. C# has picked up a lot of features to support functional programming, and has made great strides in reducing boilerplate and clutter, but there are still all sorts of things that F# has and C# either lacks, or requires a lot more verbosity to accomplish the same thing. Pattern matching, for starters. It's not just chained if-statements on steroids; F#'s decision to make partial matching emit a compiler error is a real sea change in terms of the level of compiler support you get in guarding against unintended consequences in an evolving codebase. Type providers. They let you interact with external data sources with about the level of ceremony you get in a dynamic language, but are still statically typed. The SQL type provider is particularly impressive. Not only does it generate your DTOs for you without ceremony, even when you `SELECT *`, even when the schema changes, but, if you make a mistake in an inline SQL query, you'll get red squigglies under exactly the spot in the string where the error is, just like if it had been a syntax error in the F# or C# code. Computation expressions. F#'s equivalent of Haskell's do notation. C# accomplishes similar levels of purpose-specific expressivity in some specific areas - LINQ, async/await, etc - by adding syntactic sugar to the compiler, which means only the C# compiler team gets to do it. Computation expressions let you roll your own. Currying and partial application. You can achieve the same result in C# with higher order programming, but it gets messy quickly. Also, there's an argument to be made that, similar to how objects are heavyweight closures, dependency injection is heavyweight currying.
- mattferderer 8y agoDo you have thoughts on C# 8's increased pattern matching features?
- bunderbunder 8y agoI haven't actually used C#, or any .NET language, since before 7 came out. Based on what I've seen as a sideline observer, though, it looks to me like C#'s pattern matching and destructuring are just syntacitc sugar, and therefore still significantly weaker than what F# has. I don't think you can get to the level of type safety that F#'s pattern matching provides without F#-style algebraic data types. The reason is that a set of algebraic types in F# is effectively bundle of types that are collectively sealed. In C#, you can really only seal the terminal classes in a cluster of types, which means that anyone else can come along and add a new class to the type at a later date, after the initial module is compiled, possibly even at run time. That undercuts your ability to ensure that a branching statement is airtight. I believe C# also still lacks active patterns, which are a pretty killer feature if you're looking to do data-oriented programming.
- victorNicollet 8y agoC# now has active patterns (which feel like the `is` pattern matching) in the ability to declare a variable as you pass it as an out parameter to an extension function, e.g. if (num.IsNotPrime(out var a, out var b)) WriteLine($"{num} = {a} × {b}");
- platz 8y agoany kind of pattern matching without the ability to check for exhaustiveness defeats the safety they provide, which is need to make that comparable in utility and power to inheritance (i.e. so you can actually replace inheritance w/ pattern matching.) Much like how the compiler assists you when writing subclasseses so that you've implemented all the required methods, real Pattern Matching (F#) gives you the same guarantees from the compiler that you've handled all the possible cases appropriately. Exhaustiveness checking is what elevates pattern matching to the other side of the expression problem, which is about getting feedback from the compiler to help you write programs. a glorified switch statement does not help you do that, and so you still have to write subclasses to get compiler feedback.
- bonesss 8y ago
- victorNicollet 8y agoTo this list, I would add code quotations. You can <@...@> around any expression and get a syntax tree at runtime that you can explore, transform and even compile. While C# does have a similar feature in Linq.Expressions there are entire categories of (completely banal) C# expressions that cannot be quoted.