United Kingdom: +44 (0)208 088 8978

From JS to F#

Our newest recruit Akash tells us why he made the switch over from JavaScript to F#!

I, like a lot of newer developers, learnt how to code using Javascript. I loved how quickly I could get a project up and running. However, this often came at a cost of bugs and surprises for the Q.A. team. Since JS has no type safety it's up to us developers to run through the possibilities and ensure weird bugs dont pop up - and thats hard.

What about Typescript?! Even though I got to use the awesome features that JS/TS had to offer it always felt like extra work, like fighting an uphill battle - especially with the any type in play.

The Pit Of Success

How do you win the uphill battle? Flip it on its head and make it hard to do the wrong thing. Thats why I fell in love with F#. It's a functional first language that is type safe and has all the features you love about JS, plus a lot more! The biggest difficulty I had when trying to learn a statically typed langauage was the verbose syntax, having to specify everything, coming from a world where I could just focus on the code. But with F# that isn't the case.

Here's a few direct comparisons:

1. Looping through a list and applying a function

JS

const oneToFive = [1,2,3,4,5]

const double = input => input.map(x => x * 2)

// doubleInput(oneToFive)
// [2,4,6,8,10]

F#

let oneToFive = [1..5]

let double input = input |> List.map (fun x -> x * 2) // int list -> int list
// The F# compiler has inferred that input is an int list

oneToFive |> doubleInput
val it : int list = [2; 4; 6; 8; 10]

F# works like maths - if something is on both sides of the = it can often be ommited, giving an even terser syntax

let double = List.map ((*) 2)

2. Updating a field in an object/record

JS

const person1 = { firstName: "Akash", age: 24 }

const updatePerson1 = { ...person1, age: 25 }
// {firstName: "Akash", age: 25}

F#

let person1 = {| FirstName = "Akash"; Age = 24 |} // Anonymous record

let updatePerson1 = {| person1 with Age = 25 |}
// {| FirstName = "Akash"; Age = 25 |}

// Here we define an anonymous type of Person but F# has picked up that both person1 and updatedPerson1 are both of the same type

3. Control Flow - Ternary Operator

JS

const isTrue = true ? 'This is the value' : 'Never gets reached'

F#

let isTrue = if true then "This is the value" else "Never gets reached" // string

4. Control Flow - Conditionals

JS

const findDiscount = customer => {
    if (customer === "Student") {
        return 10
    } else if (customer === "Senior") {
        return 15
    } else if (customer === "VIP") {
        return 35
    } else {
        return 0
    }
}

F#

let findDiscount customer =
    match customer with
    | "Student" -> 10
    | "Senior" -> 15
    | "VIP" -> 35
    | _ -> 0
    // string -> int

We can take this further in F# and ensure not just any string is passed in using a Choice Type or Discriminated Union

type Customer =
    | Student
    | Senior
    | VIP
    | Guest

let findDiscount customer =
    match customer with
    | Student -> 10
    | Senior -> 15
    | VIP -> 35
    | Guest -> 0
// Customer -> int

Now we have a function that takes a limited range of values and is more accurate to the domain.

From the examples above we can see that F# can be as clean, if not cleaner than JS, with full type safety. This is just a small preview of what F# is capable of, and it was enough for me to start looking into the language and eventually make the switch from JS.