Click here to Skip to main content
15,886,067 members
Articles / Programming Languages / F#

Getting Wooed by F#

Rate me:
Please Sign up or sign in to vote.
4.31/5 (8 votes)
20 Mar 2015CPOL3 min read 17.3K   6   9
Getting wooed by F#

Introduction

One of my goals this year is to learn a new programming language. This language should use a programming style different than what I am familiar with (currently C# and JavaScript). As I am settled in the .NET space, I decided to go with F#. I am only about a week in, but man I have to say I am excited. So excited that I could not hold it in any longer and decided to write about what is getting me excited. I have to stress that my F# skills are equivalent to a baby sliding around on its stomach learning to crawl. Regardless, what I have seen so far is awesome.

I am currently working through all the content on fsharpforfunandprofit by Scott Wlaschin, and I am borrowing the below example coming from there.

Modeling a Domain

So my first real surprise is how well F# lends itself to Modeling a Domain. I am going to show you this by using a card game as an example.

Here is what it might look like in C#.

C#
public enum Suit  
{
    Club,
    Diamond,
    Spade,
    Heart
}

public enum Rank  
{
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Jack,
    Queen,
    King,
    Ace
}

public class Card  
{
    public Card(Suit suit, Rank rank)
    {
        this.Suit = suit;
        this.Rank = rank;
    }

    public Suit Suit { get; private set; }
    public Rank Rank { get; private set; }
}

public class Hand  
{
    public Hand(List<Card> cards)
    {
        this.Cards = cards ?? new List<Card>();
    }

    public List<Card> Cards { get; private set; }
}

public class Deck  
{
    public Deck(List<Card> cards)
    {
        this.Cards = cards ?? new List<Card>();
    }

    public List<Card> Cards { get; private set; }
}

public class Player  
{
    public Player(string name, Hand hand)
    {
        this.Name = name;
        this.Hand = hand;
    }

    public string Name { get; private set; }
    public Hand Hand { get; private set; }
}

public class Game  
{
    public Game(Deck deck, List<Player> players)
    {
        this.Deck = deck;
        this.Players = players ?? new List<Player>();
    }

    public Deck Deck { get; private set; }
    public List<Player> Players { get; private set; }
}

Pretty straight forward stuff. I showed this to my wife that knows nothing about code and she had no idea what was going on.

Then I showed her this.

F#
module CardGame = 

    type Suit = Club | Diamond | Spade | Heart

    type Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace

    type Card = Suit * Rank

    type Hand = Card list

    type Deck = Card list

    type Player = { Name:string; Hand:Hand}

    type Game = {Deck:Deck; Players: Player list}

    type Deal = Deck -> (Deck*Card)

    type PickupCard = (Hand*Card) -> Hand

The above is not pseudo code. It valid F# that compiles. First, note the total number of lines. 80 vs 19 like what! I showed this to my wife and even though I still had to explain some of it, she got the gist just by looking at it. This means that a domain expert should fairly easily be able to confirm a domain model correctness, without understanding F#.

I know there is no behavior in the above example, but the conciseness and lack of clutter really got my attention. When the F# guys were talking about writing less code, they were not kidding.

What is not apparent from the example is that you get a lot of things for free:

  • Types are immutable by default. GoGo Value Types. Mutability can be chosen explicitly, but the immutability forces us to transform data into new data, rather than changing it. This prevents bugs and side effects.
  • Types are equatable by default. We get comparison, max, min and ordering for free. Again, this is great for Value Types.
F#
let highcard = (Heart, Ace)  
let lowcard = (Club, Six)  
highcard < lowcard //false  
let randomcard = (Club,Six)  
lowcard = randomcard //true  
  • Null reference exceptions are excluded from the above code as none of these types can be null. If you need nullable functionality, you add it explicitly.
  • New primitive types are basically free. We can easily make a string type that has to be less than 40 characters and then use that where we have a less than 40 characters business rule. Although this is possible in C#, it is a lot more code and hassle and we end up not doing it.
  • Less code means less bugs.

I am going to stop here before I re-write Scott's website. I have not even began to scratch the surface, but if what I have uncovered so far is an indication of what is to come, I am definitely going to become an F# developer.

I also found a Case Study for Type-safe Domain Modeling in F# on reddit.

If you want to find out more, have a look at the Why use F# series.

Update

To give some credit back to C#, I did the following:

  • Put all the enums on one line, even though this is not convention
  • Auto initialized the lists (available in C# 6)

This brought the line count for C# down to 55 vs 19 for f#. I then figured you can write everything on one line and that a word/character count might be a better metric. C# had 160 words and 1063 characters. F# 82 Words and 457 Characters. There is still a significant difference.

I also feel the need to say that I still love C# and I think it is a great language. This post was less about C# being long winded and more about F# being really compact.

This article was originally posted at http://feeds.feedburner.com/sneakycode

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Unknown
I write about Domain Driven Design, Clean Code and .net

Comments and Discussions

 
QuestionLiking eggs is not an option? :) Pin
Thornik23-Mar-15 9:59
Thornik23-Mar-15 9:59 
QuestionI just finished a 10 week course with Tomas Petricek Pin
Sacha Barber20-Mar-15 5:14
Sacha Barber20-Mar-15 5:14 
GeneralSharing experiance is good Pin
Ashok Kumar RV20-Mar-15 2:09
Ashok Kumar RV20-Mar-15 2:09 
QuestionBogus Comparison? Pin
KellyKimble19-Mar-15 9:45
KellyKimble19-Mar-15 9:45 
AnswerRe: Bogus Comparison? Pin
SneakyPeet19-Mar-15 18:48
SneakyPeet19-Mar-15 18:48 
Hay Kelly,

First of all I was not trying to hate on c# (I love it), I was just commenting on what grabbed my attention with f#.

The reason I did not put the enums on one line is because that is not c# convention. I did add an update to the post, where I shortened the c# and it came to about 55 lines. I also did a word and character count and I think that is more of an apples to apples comparison.

To answer your other question you can write f# like you did above.

Thanks for the comment Wink | ;)
GeneralRe: Bogus Comparison? Pin
Ashok Kumar RV20-Mar-15 1:42
Ashok Kumar RV20-Mar-15 1:42 
GeneralRe: Bogus Comparison? Pin
Member 1154262320-Mar-15 13:55
Member 1154262320-Mar-15 13:55 
GeneralRe: Bogus Comparison? Pin
SneakyPeet21-Mar-15 4:25
SneakyPeet21-Mar-15 4:25 
GeneralRe: Bogus Comparison? Pin
KellyKimble23-Mar-15 2:24
KellyKimble23-Mar-15 2:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.