Don't get me wrong -- I love F# it's a terse creature capable of solving just about any problem you can throw at -- in no less than three different ways. The list of things I love about F# is so long that it's simply quicker for me to tell you about the things I hate. I also see a lot of unfounded criticism about whether the language should exist at all, and I was hoping to direct some honest and hopefully useful criticism instead.

5. Hiding bindings

Starting with something not so bad at all, some might even call this a feature, is the effect of scope on bindings. You can bind to the same name as something in a wider scope without compilation failure. You just need to expect the outcome. For instance, it is possible to compile the following:

[sourcecode language="fsharp"]
let name = "Jim"
for i in [1..10] do
let name = name + i.ToString() // I wonder what name I'm talking to?
printfn "%s" name //oh well I hope its the same as the last line...
printfn "%s" name

//fsi output:

Jim1
Jim2
Jim3
Jim4
Jim5
Jim6
Jim7
Jim8
Jim9
Jim10
Jim
[/sourcecode]

It all makes sense, until you read the last line of output. The answer is that there are actually two different bindings to 'name', one for each scope.

Once you've seen this, it makes plenty of sense, but until you've bumped into this language feature you can be scratching your head for some time.

4. Explicit interfaces

So the main sales pitch for F# is that it allows functional programming, but it's also one heck of a swiss army knife. Doing OO in a language like F# is not only OK, its encouraged. However, once I head down this road, I'm compelled to apply good practices - namely SOLID. Interfaces form part of those practices, and though the interface story is well crafted, the last piece in the puzzle is to be able to use them implicitly.

The argument against implicit usage is really quite simple: YAGNI!

While I'm on board with this line of thinking, I still feel that it would simply be more inline with the general .NET experience, given that so much good stuff is built on C# -- and it relies on implicit interfacing to keep APIs looking neat and tidy. I shouldn't be asked to throw the baby out with the bath water when it comes to using those libraries. It's unfortunate that the following will not compile:

[sourcecode language="fsharp"]
type IFoo =
abstract Bar : string -> unit

type Foo() =
interface IFoo with
member x.Bar name = printfn "Hello %s!" name

module Baz=
let f = new Foo()
f.Bar "jimbo" //boom!

[/sourcecode]

While there is some sense in forcing a separation between interface and instance methods I find the purism a little annoying. Object expressions are a nice alternative which might solve some issues - albeit in a different way, remembering that an F# solution is simply going to be engineered differently:

[sourcecode language="fsharp"]
let f =
{
new IFoo with
member x.Bar str = printfn ( "BAZ" + str )
}
f.Bar "bam"
[/sourcecode]

Another approach is to let the compiler coerce the type for us when we pass it to a function. It baffles me that while the assignment example will not compile, we can do the following...

[sourcecode language="fsharp"]
let executeFoo (f:IFoo) input = f.Bar input
executeFoo (new Foo())
[/sourcecode]

3. Pain in the class

OO programming with F# in general is kind of weird and most of my issues lie within this segment of the language specification. Read/write properties feel clunky to me and while they're a bit new, even for C#, autoprops would still rock my world so I can avoid the following code:

[sourcecode language="fsharp"]
type Car()=
let mutable pedalPosition = 0.0
member internal self.pedalPosition
with get() = pedalPosition
and set(v) = pedalPosition <- v
[/sourcecode]

The functional zealot is going to scream at me for not using an immutable record type. The pragmatist will scream at me for not falling back on C#. I think that if F# is going to let me do things at all, it should let me do it nicely. Ideally, read/write properties would be as simple to declare as read only properties which, are very nice to declare. Maybe this could work:

[sourcecode language="fsharp"]
type Car()=
member mutable self.PedalPosition : float //read write auto property
member mutable self.IntakeTemp : <degC>
member self.IsCruising = self.PedalPosition < 0.1
member self.OpenIdleAirControlValve = self.IsCruising && self.IntakeTemp <= 50.0<degC>
[/sourcecode]

Another weirdness that gets me is the self identifier is not a keyword but a binding. While I get that it is nice, it also allows a team of 5 different developers the opportunity to have a holy war over the one true self reference. 'this', 'self', 'me', 'it' or 'x'? On top of this -- there are two scopes involved: class level self, and member level self. All told, the power that this gives you is nothing compared to the level of ambiguity you can create.

[sourcecode langauge="fsharp"]
type Person(id) as this =
do trace "created person with id {0}" this.Id
member their.Id = id
member that.FullName = that.LastName + " " + this.FirstName
member them.LastName = "Burger"
member they.FirstName = "Jim"
[/sourcecode]

This is one of those moments where the phrase: "With great power comes great responsibility" comes to mind.

2. Dependency order is important

This is a biggy, and I'm not sure what they will ever do about this, because it's apparently a pervasive issue. It's an issue that starts out as annoying, and eventually morphs into pain.

At the annoying level, we have to arrange things that make sense to the compiler. In the simplest of cases, any types that you need to use have to be implemented before you call them. In a single code file, that isn't so bad, but it is annoying. It all really takes me back to my C days:

[sourcecode language="fsharp"]
let myFunc x = someOtherFunc y //not defined!!
let someOtherFunc x = x * x
[/sourcecode]

It gets worse, because the same applies at the type level:

[sourcecode language="fsharp"]
namespace Model

type Animal(name, regTag) =
member x.Name = name
member x.Registration : RegistrationTag = regTag //not defined!!

type RegistrationTag(dateIssued, number) =
member x.DateIssued = dateIssued
member x.Number = number
[/sourcecode]

While at first you think, "OK this is just enforcing some order, that can't be bad", the problem is what if you need a circular reference? Well, to combat that edge case we have  yet another type construct we don't really want or need - mutually recursive types.

Say what? It's not nearly as bad as it sounds...

[sourcecode language="fsharp"]
open System.IO
type Folder(path) =
member x.Files = seq {
for fileName in Directory.GetFiles(path) do
yield new File(fileName, path)
}

and File(filename, parent) =
member x.Name = filename
member x.Parent = parent
[/sourcecode]

This defines two types, one referencing the other. Problem solved. Imagine now that these classes are BIG. Too bad I now have more than one type per code file!

1. Flat projects

I saved this one till last for two reasons: because it is my biggest beef thus far, but also because it is a symptom of the previous issue. Even files need to be in the correct order, by dependency, for the compiler to cope. Rather than abstracting file order and dependencies, it is coupled to the order of appearance in the project file. Sure you get some UI tools to help deal with it, but its less than ideal.

[caption id="attachment_827027" align="alignnone" width="300" caption="Its a shame that we actually need these at all."]Shows the F# UI Enhancements for handling file order[/caption]

The final blow is that this means that folders inside projects not a possibility. While I understand the reasons that forced us down this road, I don't understand why it was thought that this is a good enough solution. Personally, I think the use of folders is a necessity in any projects that has more than a handful of files. I fear that F# will never be taken seriously in the mainstream until it has a project experience similar to that of C# and VB.