Hacker News new | past | comments | ask | show | jobs | submit login
Why F# (davefancher.com)
87 points by kermatt on Jan 28, 2013 | hide | past | favorite | 30 comments



At one point the discussion turned to language productivity and Phillip remarked that writing C# feels like completing government forms in triplicate. As he elaborated I experienced a sudden burst of clarity into one of the major things that had been bothering me about C# – it’s verbosity!

It's like a parallel universe to the Scala/Java relationship.


Even more:

1. Common ascendants

Scala is heavily influenced by OCaml and Haskel.

F# is descendant of OCaml, heavily influenced by Haskel.

2. Past

Don Syme designed generics for .NET.

Martin Odersky designed generics for JVM.

3. Erlang influence

Acca - heavily influenced by Erlang and OTP, MailboxProcessor looking quite similar to Erlang processes.

4. Multiple paradigms

Both languages combine FP and imperative. Scala is more OOP, F# is more FP.

And (in my opinion) F# is looking more "clean" than Scala.

Simple thing in F#:

   let (|>) g f = f g
In Scala becames much more complicated. Also I think that discriminated unions are "prettier" than case-classes.


> Scala is more OOP, F# is more FP

That depends on your background. As far as FP goes, I wouldn't see myself working in a FP language that doesn't have type-classes or something similar. Clojure has protocols and multimethods, Scala has type-classes based on implicits, while F# doesn't have anything like that.

> F# is looking more "clean" than Scala.

I don't know about that, I got used to Scala code. As far as the languages are concerned, I hate for instance how F# imported some language features from C# that really needed to die a long time ago, like static class members and operator overloading based on said static class members. Scala on the other hand cleaned all that crap. My problem with F# is basically that it has 2 type systems in the same language. Same problem that Ocaml has really, except Ocaml can also do some pretty cool tricks with structural typing for OOP that F# cannot.

But anyway, these issues are actually irrelevant because the choice for developers will end up being the answer to ".NET or the JVM?"


I like what Odersky did with statics in Scala.

I agree that F# is not pure as Haskel and limited in comparison with OCaml and Haskel.

But the things that works in F# are working fine. In comparison with Scala: curring (by design) and tail-calls optimization are looking "more FP" in my opinion.


Yeah, but LISP doesn't do currying and I find Scala's support for currying just fine, although the syntax in F# is definitely much nicer.

Also Scala does optimize self-recursive tail-calls and it's pretty easy to work with trampolines. This is a platform limitation btw, as you can't optimize tail-calls without support from the VM. Mono, the open-source .NET implementation, also has problems with optimizing tail-calls (last time I checked) and I don't know about .NET 4.5, but .NET 4 was not optimizing tail-calls on 64-bits Windows. I remember reading a blog post about them fixing it on 64-bits OS in the latest version, but it wasn't the kind of feature you could rely on in the past.

I do have hopes that TCO will make it into the JVM at some point, as there are experiments for it available as part of OpenJDK. Unfortunately the JVM moves at a glacial pace in regards to such features. This is both a blessing and a curse.

I do agree with you. Not having full TCO in a functional language kind of sucks.


   and I don't know about .NET 4.5, but .NET 4 was not
   optimizing tail-calls on 64-bits Windows. 
Actually there's a .tail CLI Opcode in .NET for tail call optimization which is not usually emitted, but the JIT does tail call optimization on 64 bits (not on 32 bits though). You can witness this when you have a C# getter calling itself. On 32 bits, you get a StackOverflowException, on 64 bits it keeps running happily forever. For the specifics: https://blogs.msdn.com/b/clrcodegeneration/archive/2009/05/11...

It's lower level and more limited than full blown FP aware TCO and it may not catch every call pattern, but it's been there for a while.


.NET 4 most certainly does optimize tail-calls, and the 64-bit versions of the CLR contain additional optimizations that the 32-bit versions don't.

In fact, F# is able to target previous version of the CLR (.NET 2.0, 3.0, and 3.5) and I know for a fact that they also support the 'tail.' opcode and perform some TCO (though it handles fewer edge-cases than .NET 4.0 and 4.5).


Forgive my ignorance, but what is wrong with static class members?


I don't know any theoretical explanation, but I try explain it.

You see static String.Split and normal method Split of String objects.

First method does not belong to string objects, it belongs to String class.

String class is an object itself, so why not make this distinction more explicit?

It exactly so in Scala: classes are classes and all static members goes to companion objects. Companion objects by nature are singletones.

I think it's much more natural this way than in C++/Java/C#. Everything on its place, even singletones became elegant.


I don't think there is much point in trying to phrase it in terms of what X has that Y doesn't, such comparisons are fraught will peril and are more indicative of a person's past decisions on what language to take. Better to talk about trade offs. Each language has a trade off that is not a big deal in terms of language capabilities. For Ocaml it is multithreading, for Scala lack of TCO+limited inference, for Haskell it's packages and for F# it's compatibility with .NET.

Those features [type classes,structural (sub)typing] you mention as being a problem simply aren't really missed due to other things on offer. While F# does not have type classes (non erasure has it's advantages to ease that lack) you don't really notice it as it turns out that kind of power is pivotal in a handful of cases and for that F# has these statically resolved type parameters which do a kind of static duck typing that is good enoughTM. The static overloading is not hit and the static methods are useful the way F# implements them (makes things simple, not as annoying or cumbersome as in C#).

Most of the time computation expressions and or simple abstract classes or interfaces with object expressions , occasionally coupled with active patterns are more than good enough for the kind of places type classes might otherwise be used. Personally, I try to make simple choices so that algebraic datatypes and records are all that is needed. I'm allergic to fancy code. I mentioned active patterns, they are really quite powerful - at the same level of power as multimethods (I have used them to solve an expression problem type thing). I believe that the use of Active Patterns and Quotations in F# is more common than in Scala due to choices in where power focus lie. I also find F#<->C# interop to be a bit easier than Scala<->Java interop for the same reason that C# -> F# objects are basically injective while Java -> Scala is only a subset.

I also think F# is more functional than Scala. Scala is supposed to be something different: a successful melding of OOP and functional. And it is the best at that I have seen. It succeeds on this better than the next biggest contender: F#. F# is more typically functional, using the usual Hindley Milner Inference and sharing a core with OCaml but with significant whitespace. So it can be very succinct. Typically functional idioms like algebraic data types, Piping, point free, currying and combinators is more natural to F# than Scala's more OOP way.

There are a number of things that Scala does naturally that are cumbersome in other languages because of how it manages to meld a powerful combination of orthogonal features. To use Scala as just another functional language is to miss its power. Those who criticize OOP have not used a language that does it right. Abstractly, in a simplified categoric setting, we can consider Abstract types (objects as an aproximation as coalgebras) and FP (algebraic data types) as duals of each other. A proper unification of the concepts gives something more flexible than either. I think Scala comes the closest. Sure you can be 100% functional in it, or replicate Java but to call it one or the other is to make the same mistake as to say that light is both a wave and a particle and think you understand what that means.


Isn't the first C# example (the class) a pessimization? Why not e.g.

    public class CircleMeasurement
    {
        public double Diameter { get; private set }
        public double Area { get; private set }
        public double Circumference { get; private set }
        public CircleMeasurement(double diameter, double area, double circumference)
        {
            Diameter = diameter;
            Area = area;
            Circumference = circumference;
        }
    }
Arguably there's still a fair bit of repetition due to the constructor, compared to the F# code (and I'm not sure object initializers can be used with private-set properties), but a third of the repetitions have been skipped through implicit backing fields.


And he didn't even implement equality and comparison yet!


Also most of that code can be written automatically with Resharper...


Resharper isn't going to read it for you.


This. I love IDEs, but arguments like 'the tool can generate $GARBLE for me!' are what keeps the haters a-hatin' and the mediocre programmers mediocre.


I am a .NET developer by trade, and any other .NET developers I know that have heard of F# love the idea of it and would happily use it. The sad part is that this is often as far as it goes.

I think C# is a fantastic language, but if the development of F# got to the point where I could swap out either language when building an ASP.NET website with no worries about compatibility or missing out on anything (ReSharper being a big one) I would happily use F# on a project, and I'm willing to bet that many other developers would.

What seems to be holding off many people, including myself, is a lack of knowledge and information about F# from the higher-ups.


Being able to simultaneously develop in an imperative language (C#) and also a functional language (F#) at the same time on a project can be very appealing depending on what one is doing. With .net or mono, it makes it pretty easy to switch between them.

Sometimes I like having the power to use a functional language for a certain task, but would rather not develop an entire project with one. C# does have functional abilities (Linq), but it's not quite the same.


Agreed. I recently wrote my first F# code because the boilerplate associated with emulating pattern matching/discriminated unions in C# was so unappealing. I very much like the ability to wrap a piece of pure F# code in a C# API. I actually think the resulting F# is easier to explain to another developer than a huge collection of visitor classes.

I also feel that I wouldn't want to write the whole app in F#, because I don't feel like the OO/FP approach feels as natural for some parts of the app as plain old C#.


Oh yeah, visitor would be a great example since F# has support of multiple dispatch. When I learned the Visitor pattern at the University I attended, it was one of the hardest things to wrap my head around initially until it finally clicked what it was while writing the code. It's just so counter intuitive to what most would think imperative language design is initially that it can take a bit to sink in. It seems simple enough, but trying to understand it and implement it are two different beasts. I would have gladly done it in a functional language or a Lisp variant if given the option.

Having to explain the Visitor pattern though to someone else would be much more painful than that I imagine versus just writing and explaining it in F#. The code just reads much more naturally for it, since the language supports it without a quirky design pattern.


Could you elaborate on your last sentence? Especially with F# 3, the OO features should be syntactically the same as C#. You can use F# as a light-syntax C#, really, with a few minor caveats.

For curiosity, what in particular do you find to be unnatural in F#?


I'm just not really a fan of mixing OO or imperative and FP code in the same code unit, with the exception of a few things like LINQ which might be called FP. For anything with a lot of mutation or tight loops, I'd rather stick with C#, and save myself the hassle of explaining the code to other devs later on. The idea of one language for everything is nice, but C# has carved out a place for itself, and maybe F# should try to focus on those areas where it can differentiate itself by effecting shorter, more self-describing code.


>>I actually think the resulting F# is easier to explain to another developer than a huge collection of visitor classes.

Yes. It's even possible in some cases to use F# source as some kind of pseudo-code with C#-programmers.


This is what I did with WcfStorm.Server and WcfStorm.Rest (https://www.wcfstorm.com). The UI layer was written in C#; all other layers in F#. Switching back and forth though between an OO and an FP language (at least from my experience) is not that easy. There were a few instances where I ended up writing a class with mutable properties in F# simply because I didnt want to break my chain of thought so that I can get a feature out quickly


Yeah! I love using as many languages as possible with my projects too, that way I can raise the "barrier to entry" to a codebase as high as possible--which comes in really handy if, for example, other folks you work with would otherwise hit you with drive-by craptacular changes that break your pristine codebase (that with any luck you have to clean up yourself afterwards). Also, lets not forget about another nice side-effect: added job security.


Given that the two comments by pohl and yareally are appreciative of a functional language that interoperates well with a host language, I would like mention Felix, a language I have been lloking at the past few weeks.

It is whole program optimized, strongly typed, polymorphic, ML like language without a default evaluation order that can interact effortlessly with C and C++ code and compiles down to C++, another differentiator is the presence of coroutines

I can point to two tutorials. One explains Felix by beginning from C++ [1], the other describes Felix the language [2].

[1] https://felix-lang.org/web/nutut/intro/intro_index.fdoc

[2] https://felix-lang.org/web/tutorial.fdoc

No analogies are correct, but roughly

Felix is to C++ what Scala is to JVM (or F# is to C#). Note however Felix predates all these languages.

@Ingaz the analogy is a little more literal because Felix compiles down to C++ (unlike OCaML)


Interesting.

But I always thought that OCaml to C++ is what F# to C#.


Specially given OCaml's industry support, mainly in finance.


Sounds much like my own experiences. I recently wrote some APIs in C#, and was reminded just how verbose and limited my writing becomes.

Even if I'm writing code that's not very functional, using F# as a better C# seems to work very well.

The main reasons to use C# are for legacy interop and perhaps if the code isn't a major focus and hiring someone capable of writing F# would actually be a limitation. Some folks also feel F# is clunky for imperative code; I haven't really felt that way.


That's great. Will F# get support from Microsoft for our enterprise? Nearly every server is either HPUX, AIX or Solaris. There are a few blade servers running Linux. Java runs on every one of these platforms with great vendor support. What can we expect from Microsoft if we switch to F#? This is the reality of large monolithic parastatal enterprise.


The .Net Platform is a massive enterprise mainstay.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: