By Adam Granicz on Thursday, September 30, 2010 — 0 comments

Tutorial: Implementing a shopping cart with WebSharperCore team

Last week I had a Community for F# talk on WebSharper where I presented a small WebSharper application to implement a client-based, persistent shopping cart, and I received numerous emails asking for the source code for that talk. So in this post I am going to show you the full source code and walk you through what I did to implement the shopping cart functionality. The code provided here should work on any existing 1.0.X installation, preferably on the latest 1.0.28 release.

What's so special about this implementation?

  • First of all, it's all done with F# code with minimal markup involved to implement a site master page.
  • It demonstrates how easily you can write entire web applications in F# and integrate seamlessly with ASP.NET.
  • Despite its shortness, this shopping cart implementation can handle multiple product categories and display various products under in each category.
  • It is implemented entirely in client-side code, except for the initial call to the server to fetch the available products and families. Therefore, adding to, or removing items from the shopping cart, and calculating the total sum is handled entirely on the client, without any server-side intervention. This makes the application fast and highly interactive.
  • The application demonstrates just how easily you can enlist external JavaScript libraries in your WebSharper applications, all with F# code.

Building a shopping cart - the parts needed

There are three main parts to this WebSharper application. First, you need a design for how the page should look, second you need a WebSharper binding for the chosen client-side persistency framework, and third you need the WebSharper code for the main functionality of the shopping cart. We will discuss each of these below.
To get started, you should create a new WebSharper application in Visual Studio. If you don't have WebSharper installed, you can search for the WebSharper Standard plugin in the Visual Studio Gallery (in Visual Studio 2010, go to Tools / Extension Manager, and search for WebSharper in the Online Gallery), or download WebSharper Standard from our web site directly.

The following screenshot shows how your solution will eventually look like in the Visual Studio Solution Explorer.

Step 1 - Getting the design done

With WebSharper Standard, the primary way to expose your WebSharper applications is via ASP.NET. You will see shortly how easily you can accomplish this. In this first step, however, you will create a basic master page and populate the web application project in your WebSharper solution with a couple pages.

First, note that I am showing an out-of-project design.html file in the WebApplication project. This I used to create a basic HTML layout page that will serve as my ASP.NET master page. I then took this design and transliterated it to the following master page:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<%@ Master %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<!-- Head -->
<head id="Head1" runat="server">
    <title>Your site title</title>
    <link href="reset.css" rel="stylesheet" type="text/css" />
    <link href="site.css" rel="stylesheet" type="text/css" />
    <WebSharper:ScriptManager runat="server" ></WebSharper:ScriptManager>
</head>
<body>
    <form runat="server">
    <table>
        <tbody>
            <tr>
                <td colspan="2" id="menu">
                    <div>
                        <asp:HyperLink runat="server" NavigateUrl="~/Flowlet.aspx">
                            Flowlet</asp:HyperLink> |
                        <asp:HyperLink runat="server" NavigateUrl="~/ShoppingCart.aspx">
                            Shopping Cart</asp:HyperLink>
                    </div>
                </td>
            </tr>
            <tr>
                <td colspan="2" id="banner">
                    <asp:ContentPlaceHolder runat="server" ID="Title">
                    </asp:ContentPlaceHolder>
                </td>
            </tr>
            <tr>
                <td id="main">
                    <asp:ContentPlaceHolder runat="server" ID="Main">
                    </asp:ContentPlaceHolder>
                </td>
                <td id="side">
                    <asp:ContentPlaceHolder runat="server" ID="Side">
                    </asp:ContentPlaceHolder>
                </td>
            </tr>
            <tr>
                <td colspan="2" id="footer">
                    WebSharper™ demo by Adam Granicz, IntelliFactory.
                    Absolutely no warranty of any kind :)
                </td>
            </tr>
        </tbody>
    </table>
    </form>
</body>
</html>

I won't inline reset.css and site.css here, you can find them in the attachment zip file in the bottom of this article. As you would expect, the former implements some basic "reset" on the HTML styles, and the latter implements the look and feel for the mini-site.

The master page with a default instantiation looks like the following:

With this new master page, you can add a couple new pages and modify the default page to have links to both. Here is Flowlet.aspx - which wraps the SignupSequence pagelet (renamed to signup.fs in WebSharperProject) from the "default" WebSharper project that I left for the sake of having two different pages in our mini site:

1
2
3
4
5
6
7
8
9
<%@ Page MasterPageFile="~/site.master" %>

<asp:Content ContentPlaceHolderID="Title" runat="server">
    <h1>Flowlets Demo</h1>
</asp:Content>

<asp:Content ContentPlaceHolderID="Main" runat="server">
    <ws:SignupSequence runat="server" ></ws:SignupSequence>
</asp:Content>

Note that I did have to make a couple small changes in signup.fs from the default, namely I switched the formlet and flowlet declarations to be lazy, so I have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[<JavaScript>]
let BasicInfoForm () : Formlet<BasicInfo> =
    ...

[<JavaScript>]
let ContactInfoForm () =
    ...

[<JavaScript>]
let SignupSequence () =
    ...

[<JavaScript>]
override this.Body = ContactForms.SignupSequence ()

These were necessary because the code in the default project template assumes that these formlets are created eagerly - that is for every pagelet inside your WebSharper application. However, in our shopping cart application this is not true - so you need to switch those formlet/flowlet constructions to be on demand.

The ShoppingCart.aspx file is just as simple as Flowlet.aspx, simply filling the content holes of the master page and exposing the two WebSharper controls (ItemsToBuy and ShoppingCart) we are about to develop.

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ Page MasterPageFile="~/site.master" %>

<asp:Content ContentPlaceHolderID="Title" runat="server">
    <h1>Your Shopping Cart</h1>
</asp:Content>

<asp:Content ContentPlaceHolderID="Main" runat="server">
    <ws:ItemsToBuy ID="ItemsToBuy1" runat="server" ></ws:ItemsToBuy>
</asp:Content>

<asp:Content ContentPlaceHolderID="Side" runat="server">
    <ws:ShoppingCart ID="ShoppingCart1" runat="server" ></ws:ShoppingCart>
</asp:Content>

Step II - Wrapping Persist.js

Before we develop the shopping cart functionality, we need an API for saving to and retrieving values from a client-side persistent storage. This machinery will give us the necessary functions to operate on the shopping cart state.

A quick look around the web for client-side persistent storage reveals several compeling choices. For one, we could use HTML5 Web Storage - however, its implementation is lagging behind in different browsers. Another alternative, PersistJs seems much more viable as it promises widespread backwards compatibility, so I decided to use that.

A quick look at the PersistJs samples reveals a very simple, to-the-point API. You can do three main things:

  • Create or fetch a new store by name
  • Save some string data at a given string key in a store.
  • Retrieve asynchronously the value assigned to some key in a store.

We will need to store arbitrary values in the store, so this API needs some slight adjustments as we migrate it over to WebSharper. For this, we need a way to marshal arbitrary values to strings and unmarshal them back to values of their appropriate type.

Below is the full implementation of the PersistJs WebSharper bindings (WebSharperProject/persistjs.fs):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
namespace IntelliFactory.WebSharper.PersistJs

open IntelliFactory.WebSharper

module internal JSON =

    [<Inline "JSON.parse($x)">]
    let Parse<'T> (x: string) : 'T = Unchecked.defaultof<'T>

module Dependencies =
    open System
    open System.Configuration
    open IntelliFactory.WebSharper

    let internal PersistJsBase =
        let key = "IntelliFactory.WebSharper.PersistJs"
        match ConfigurationManager.AppSettings.[key] with
        | null ->
            "/js/persist-js"
        | url ->
            url

    [<AbstractClass>]
    type JsResource(fname: string) =
        interface IResource with
            member this.Render (resolver, writer) =
                let loc = sprintf "%s/%s" PersistJsBase fname
                Resource.RenderJavaScript loc writer

    type PersistJs() = inherit JsResource("persist-min.js")

[<Require(typeof<Dependencies.PersistJs>)>]
[<JavaScriptType>]
type Store =
    [<Inline "new Persist.Store($name)">]
    static member Create (name: string) : Store =
        failwith "Client-side"

    [<Inline "$this.set($key, JSON.stringify($value))">]
    member this.Save<'T> (key: string, value: 'T) : unit =
        failwith "Client-side"

    [<Inline "$this.get($key, $callback)">]
    member private this.RetrieveP (key: string, callback: bool*string->unit) : unit =
        failwith "Client-side"

    [<JavaScript>]
    [<Inline>]
    member this.Retrieve<'T> (key: string) : Async<'T option> =
        Async.FromContinuations <| fun (onOk, onExc, onTerm) ->
            this.RetrieveP(key, fun (ok, str) ->
                if ok && str <> null then
                    onOk (Some (JSON.Parse<'T> str))
                else
                    onOk None)

    [<JavaScript>]
    [<Inline>]
    member this.Contains (key: string) : Async<bool> =
        Async.FromContinuations <| fun (onOk, onExc, onTerm) ->
            this.RetrieveP(key, fun (ok, str) ->
                if ok && str <> null then
                    onOk true
                else
                    onOk false)

In this code, the internal JSON module supplies the Parse member, this performs the unmarshalling needed for retrieving values from the store. Marshalling is inlined via the native JSON.stringify function.

While the above code is pretty straightforward, the Dependencies module deserves some mention. First, we define an abstract class that represents JavaScript resources relative to a base location. This base location defaults to the /js/persist-js folder on the web server, but can also be overriden via Web.Config. Finally, we define the persist-min.js (available from the PersistJs site) artifact as a JavaScript resource. Note how this resource is then annotated on the main Store type as a resource requirement. This causes the WebSharper script manager (that is present in our master page) to inline a reference to persist-min.js when this Store class is in use in the current page.

Part 3 - Implementing the shopping cart

Now you are ready to implement the main shopping cart functionality. This has two parts- a listing of available products broken down by category, and the shopping cart that summarizes the items already in the cart.

Below is a mockup of these two "controls" and the events that can originate from both.

Note that both the ItemsForSale and the ShoppingCart controls can originate events, but only the latter one can react to them visually. You can implement these events in a variety of ways. In my talk I mentioned several alternatives:

  • Implementing a simple message queue, such as a MailBox
  • Hosting ItemsToBuy and ShoppingCart in a parent pagelet and handling their communication locally in that pagelet
  • Using the upcoming RxJs bindings for WebSharper, and implementing the shopping cart as an observable collection via reactive programming
  • Using simple F# events - where both controls trigger various events, and the ShoppingCart control subscribes to the shared event channel and responds visually as appropriate

For this implementation I chose the last option, implementing the communication between the two pagelets using F# events. This is a strikingly simple yet effective approach that works perfectly on the client-side.

So without further due, let's jump into the main shopping-cart.fs module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
namespace WebSharperProject

open System
open IntelliFactory.WebSharper
open IntelliFactory.WebSharper.Html

module ShoppingCartInternals =
    module M = Microsoft.FSharp.Collections.Map

    module Internals =

        [<JavaScript>]
        let internal store () = PersistJs.Store.Create "shopping-cart-4"

        [<JavaScript>]
        let NextCounter () =
            let setCounterTo i =
                (store ()).Save<int>("counter", i)
            async {
                let! currOpt = (store ()).Retrieve<int> "counter"
                let current =
                    match currOpt with
                    | None ->
                        0
                    | Some curr ->
                        curr
                let res = current+1
                setCounterTo res
                return res
            }

        [<JavaScript>]
        let SetItemsInCart items =
            (store ()).Save<(string * (string*float*int*int)) array>("cart", items)

        [<JavaScript>]
        let GetItemsInCart () : Async<Map<string, (string*float*int*int)>> =
            let getCart () =
                (store ()).Retrieve<(string * (string*float*int*int)) array> "cart"
            async {
                let! res = getCart ()
                let newres =
                    match res with
                    | None ->
                        SetItemsInCart [||]
                        [||]
                    | Some items ->
                        items
                let res =
                    newres
                    |> M.ofArray
                return res
            }

The above code encapsulates the persistent storage-related functionality into the Internals module. Here, the internal store function creates or fetches a store by name, NextCounter supplies an increasing stream of numbers (implemented via storing the last "ticket" number in the persistent store) that you use for ordering items that are added to the cart (last added is shown last), SetItemsInCart, and GetItemsInCart store and retrieve all items in the cart, respectively (we do this as a batch operation since our PersistJs binding doesn't expose an API for enumerating all entries in a given store).

The events you saw earlier are modeled as a union type (CartEvent) and the main event channel (ShoppingCartEvents) is a simple F# first-class event that communicates CartEvent values:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    module Events =
        type Item =
            { ProductName : string
              Title: string
              Price: float }

        type CartEvent =
            | AddItem of Item * int
            | AddOneItem of string
            | RemoveOneItem of string
            | RemoveItem of string
            | EmptyCart

        [<JavaScript>]
        let ShoppingCartEvents = new Event<CartEvent> ()

The only time we need to contact the server is when we fetch the available products and their categories. This is encapsulated in the Server module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    module Server =
        type CartFamily =
            { Title : string
              Products : CartProduct list }

        and CartProduct =
            { Title : string
              ProductName : string
              ImageSrc : string
              Price : float }

        /// Computes the families and the products inside them that are
        /// available for download.
        [<Rpc>]
        let ComputeFamiliesAndProducts () : CartFamily list =
            let T imageSrc (title, id, price) =
                { Title = title
                  ProductName = id
                  ImageSrc = imageSrc
                  Price = price }
            let laptop prod = T "/images/laptop.png" prod
            let desktop prod = T "/images/desktop.png" prod
            let netbook prod = T "/images/netbook.png" prod
            [ { Title = "Laptops"
                Products =
                  [ laptop ("Toshiba", "id1", 1299.0)
                    laptop ("HP", "id2", 1499.0)
                    laptop ("Dell", "id3", 1499.0)
                    laptop ("Acer", "id4", 1499.0) ] }
              { Title = "Desktops"
                Products =
                  [ desktop ("Gamer 1", "id11", 699.0)
                    desktop ("Gamer 2", "id12", 799.0)
                    desktop ("Office", "id13", 599.0)
                    desktop ("Server", "id14", 1299.0) ] }
              { Title = "Netbooks"
                Products =
                  [ netbook ("Entry", "id21", 799.0)
                    netbook ("Medium", "id22", 899.0)
                    netbook ("Cool", "id23", 699.0)
                    netbook ("Speed-King", "id24", 999.0) ] } ]

Here, each product has a title that we display (such as "Dell"), a corresponding product name we use to identify the product (such as "id3"), a URL that points to the image that represents the product, and a price (we assume dollars).

You will also need a tiny utility function to create buttons:

1
2
3
4
5
    module WebControls =

        [<JavaScript>]
        let Button label =
            Input [Type "button"; Value label; Width (label.Length*15 |> string)]

With the internal, event-, and server-relared abstractions, you can now implement the actual client-side controls. The "design" for these controls is taken from our initial HTML mockup (design.html), transliterated into a nested HTML combinator structure with further F# code to populate it with actual data. The Client module has the function that is called when the user checks out - I left this function empty, but this is the place where you would normally process payment, etc.

1
2
3
4
5
    module Client =
        /// Sends payment.
        [<JavaScript>]
        let SendPayment (items: (string * (string*float*int*int)) list) =
            ()

The ItemsForSale control fetches all product families from the server and displays them.

1
2
3
4
5
6
7
8
9
        /// Displays all item categories and their items for sale.
        [<JavaScript>]
        let ItemsToBuy () =
            let families = Server.ComputeFamiliesAndProducts ()
            Div [Id "shopping-cart"] -< [
                families
                |> List.map (fun family ->
                    Div [Class "family"] -< [
                        H1 [Text family.Title]

For each family, you list all products therein by iterating through the Products collection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
                        family.Products
                        |> List.map (fun product ->
                            let input = Input [Type "text"; Value "1"]
                            Div [Class "product"] -< [
                                Img [Alt product.Title; Src product.ImageSrc]
                                Div [
                                    H1 [Text product.Title]
                                    P [
                                        Code [Text ("$" + string product.Price)]
                                    ] -< [
                                        Text " / item"
                                    ]
                                    P [
                                        Text "Quantity:"
                                    ] -< [
                                        input
                                    ]

The "Add to cart" button triggers a CartEvent.AddItem event that carries the product data:

1
2
3
4
5
6
7
8
9
10
11
12
                                    WebControls.Button "Add to cart"
                                    |>! OnClick (fun e args ->
                                        Events.CartEvent.AddItem (
                                            { ProductName=product.ProductName
                                              Title=product.Title
                                              Price=product.Price },
                                            (int input.Value))
                                        |> Events.ShoppingCartEvents.Trigger
                                    )
                                ]
                            ]
                        )

Finally, you add a "closer" DIV to render each family nicely under one another.

1
2
3
4
5
6
7
8
9
                        |> fun products ->
                            products @ [
                                Div [Style "clear:both;"]
                            ]
                            |> Div
                    ]
                )
                |> Div
            ]

The ShoppingCart control is slightly more complex as it needs to handle the various events that come through the ShoppingCartEvents channel. But first, you define a placeholder for the shopping cart (contents), and a function that updates this placeholder with the items in the cart:

1
2
3
4
5
6
7
8
9
10
        /// Displays the shopping cart.
        [<JavaScript>]
        let ShoppingCart () =
            let contents = Div []
            let updateCart () =
                async {
                    let! itemsInCart = Internals.GetItemsInCart ()
                    contents.Clear ()
                    Div [Id "shopping-cart-contents"] -< [
                        H1 [Text "Shopping Cart"]

Each item in the cart will be displays as a row in a table. Furthermore, cart items are sorted by their order. You also need to the total cost of all items in the cart, so you fold through the sorted item list, with some minor logic to alternate row styles:

1
2
3
4
5
6
7
8
9
10
                        Table [
                            itemsInCart
                            |> M.toList
                            |> List.sortBy (fun (_, (_, _, _, order)) -> order)
                            |> List.fold (fun (i, acc, sum) (product, (t, p, q, o)) ->
                                let alt =
                                    if i%2 = 1 then
                                        "alt "
                                    else
                                        ""

For each item, you display a set of buttons, each firing their corresponding events, and accumulate the total cost:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
                                (i+1, acc @
                                 [
                                    TR [Class alt] -< [
                                        TD [Class "col1"] -< [
                                            WebControls.Button "-"
                                            // What happens when we click "-"?
                                            |>! OnClick (fun e args ->
                                                product
                                                |> Events.CartEvent.RemoveOneItem
                                                |> Events.ShoppingCartEvents.Trigger
                                            )
                                            Div [Class "count"] -< [q|>string|>Text]
                                            WebControls.Button "+"
                                            // What happens when we click "+"?
                                            |>! OnClick (fun e args ->
                                                product
                                                |> Events.CartEvent.AddOneItem
                                                |> Events.ShoppingCartEvents.Trigger
                                            )
                                            WebControls.Button "X"
                                            // What happens when we click "Remove"?
                                            |>! OnClick (fun e args ->
                                                product
                                                |> Events.CartEvent.RemoveItem
                                                |> Events.ShoppingCartEvents.Trigger
                                            )
                                            Div [Class "title"] -< [Text t]
                                        ]
                                        TD [Class "col2"] -< [
                                            Code [
                                                Text (string p)
                                            ]
                                        ]
                                    ]
                                 ], sum + (float q)*p)
                            ) (0, [], 0.)

Finally, you wrap up the items with displaying the totals:

1
2
3
4
5
6
7
8
9
10
11
12
                            |> fun (_, rows, sum) ->
                                rows
                                |> fun rows ->
                                    rows @ [
                                        TR [ Hr [] ]
                                        TR [
                                            TD [Text "Total:"]
                                            TD [Code [sum |> string |> Text]]
                                        ]
                                    ]
                                    |> TBody
                        ]

And last, you add the "Checkout" and "Empty cart" buttons - both clearing the cart contents.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
                        Div [Style "height:20px"] -< []
                        Div [
                            WebControls.Button "Checkout"
                            |>! OnClick (fun e args ->
                                Window.Alert "Checkout!"
                                // Process payment
                                itemsInCart
                                |> M.toList
                                |> SendPayment
                                // Empty shopping cart
                                Events.CartEvent.EmptyCart
                                |> Events.ShoppingCartEvents.Trigger
                            )
                            WebControls.Button "Empty cart"
                            |>! OnClick (fun e args ->
                                Events.CartEvent.EmptyCart
                                |> Events.ShoppingCartEvents.Trigger
                            )
                        ]
                    ]
                    |> contents.Append
                }
                |> Async.Start

Handling the events that come through the event channel is done by subscribing to that event channel, matching on the various events that come in and do the right thing for each:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
            Events.ShoppingCartEvents.Publish.Add (fun ce ->
                async {
                    let! itemsInCart = Internals.GetItemsInCart ()
                    let! next = Internals.NextCounter ()
                    let SET items =
                        items |> M.toArray |> Internals.SetItemsInCart
                    let _ =
                        match ce with
                        | Events.CartEvent.AddItem (item, qty) ->
                            let qN, o =
                                if M.containsKey item.ProductName itemsInCart then
                                    let _, _, qO, o = itemsInCart.[item.ProductName]
                                    qO + qty, o
                                else
                                    qty, next
                            itemsInCart
                            |> M.add item.ProductName (item.Title, item.Price, qN, o)
                            |> SET
                        | Events.CartEvent.RemoveOneItem productName ->
                            if M.containsKey productName itemsInCart then
                                let t, p, q, o = itemsInCart.[productName]
                                if q <= 1 then
                                    itemsInCart
                                    |> M.remove productName 
                                else
                                    itemsInCart
                                    |> M.add productName (t, p, q-1, o)
                                |> SET
                        | Events.CartEvent.AddOneItem productName ->
                            if M.containsKey productName itemsInCart then
                                let t, p, q, o = itemsInCart.[productName]
                                itemsInCart
                                |> M.add productName (t, p, q+1, o)
                                |> SET
                        | Events.CartEvent.RemoveItem productName ->
                            itemsInCart
                            |> M.remove productName
                            |> SET
                        | Events.CartEvent.EmptyCart ->
                            M.empty
                            |> SET
                    do updateCart ()
                }
                |> Async.Start
            )

And finally, you display the cart contents and return the placeholder element:

1
2
            updateCart ()
            contents

Conclusion

In this tutorial, you saw how you can bind and use existing JavaScript libraries with WebSharper and implemented a client-based persistent shopping cart based on PersistJs. You used asynchronous workflows to model fetching values from the persistent store, and F# events for modeling the communication between two pagelets that made up your shopping cart application.

AbstractShoppingCart.zip

By Adam Granicz on Friday, August 6, 2010 — 0 comments

WebSharper available in Visual Studio GalleryCore team

WebSharper 2010 Standard is now available through Visual Studio Gallery, complementing among others the great F# templates from Daniel, and those announced in Don's earlier article.
You can either search for WebSharper in the Extension Manager (under Tools) in Visual Studio 2010, or go to the Gallery page directly.

Click Download, walk through the couple steps of the installer, and you are good to go. The Gallery page also provides a few quick pointers, but be sure to check out the WebSharper main page and the demos page to get started.

By Anton Tayanovskyy on Tuesday, June 29, 2010 — 0 comments

Optimizing JavaScript with F#Core team

These days WebSharper™ trenches are teeming with activity as we are busy preparing the next major release of the platform. One of the F#-to-JavaScript compiler highlights of the new release is a host of optimizations on the JavaScript output. Designing these optimizations with F# was quite rewarding, and I am sharing some of the eurekas in this blog.

The need for optimizing JavaScript is very peculiar. This is not about delivering top wall-clock performance, but rather delivering the most compact (in Release mode) and most readable (in Debug mode) source. In the case of WebSharper™, it is also about relieving the compiler and the macro writer from the burden of emitting optimal code. Essentially, we would like to conform to the Macro Writer's Bill of Rights, for JavaScript.
The optimizations covered today include:

  • constant folding
  • inlining
  • redex elimination
  • common subexpression elimination

The problem with optimizing JavaScript is that it is complex. There are expressions, statements, objects, field assignments and what not. Scoping of variables is not functional, there are no let statements (we target the 3rd edition of ECMA-262). Any of the above optimizations are non-trivial on the complete JavaScript AST.

For this and other reasons, we ended up designing an intermediate representation, Core JavaScript. Unlike complete JavaScript, Core JavaScript is functional, simple, and very easy to optimize. In fact, Core JavaScript expressions instantiate Core Scheme expressions parameterized by a primitive set. Here is the definition of a Core Scheme expression:

1
2
3
4
5
6
7
8
9
10
type Expression<'P> =
    | Apply of E<'P> * list<E<'P>>
    | Assign of Id * E<'P>
    | If of E<'P> * E<'P> * E<'P>
    | Lambda of list<Id> * E<'P>
    | Let of Id * E<'P> * E<'P>
    | LetRecursive of list<Id * E<'P>> * E<'P>
    | Primitive of 'P * list<E<'P>>
    | Undefined
    | Var of Id

The good news is that while Core JavaScript is fully as expressive and in fact very close to the complete JavaScript, we can now write optimizations as transformations on Core Scheme expressions that preserve the (simple) Scheme semantics. For example, common subexpression elimination looks for matching pure, ground subexpressions, and lifts them to a Let binding. And of course not having to deal with expression/statement distinction, this argument passing convention, and the like is the joy for the compiler or macro writer.
Example 1: Eliminating Common Subexpressions

1
2
3
4
5
6
7
let x = Id "x"
let y = Id "y"
let this = Id "this"
E.Array [
    E.Function this [x; y] (!^this .% !^x ..% [!^y])
    E.Function this [x; y] (!^this .% !^x ..% [!^y])
]

Note: ( !^ ) :: Id -> Expression lifts identifiers to expressions.
This outputs:

1
2
3
4
5
6
7
8
9
(function ()
 {
   var _;
   function _(x, y)
   {
     return this[x](y);
   }
   return [_, _];
 })()

Example 2: Inlining and Constant Folding

1
2
3
4
5
E.Let y (E.Int 1) (
    E.Let x (E.Int 2) (
        !^x +% !^y
    )
)

Outputs:

1
2
3
4
(function ()
 {
   return 3
 })()

Example 3: Redex Elimination and Constant Folding

1
2
E.Function this [x] (!^x +% E.String "!") 
    ..% [E.String "Hello"]

Outputs:

1
2
3
4
(function ()
 {
   return "Hello!"
 })()

Writing the optimizations was a joy. For example, the inlining transformation is within 20 lines of F#.

The largest contribution to the joy is the fact that the underlying engine takes care of JavaScript insanity.

For instance, using the same suggested variable names gives valid JavaScript code by disambiguating variables:

1
2
3
4
5
E.Let x (L?foo ..% []) (
   E.Let x (L?bar ..% [!^x]) (
      L?baz ..% [!^x]
   )
)

Outputs:

1
2
3
4
5
6
7
(function ()
 {
   var x, x1;
   x = foo();
   x1 = bar(x);
   return baz(x1);
 })()

As a final example, this-style variables are automatically handled when captured, for example:

1
2
3
4
5
E.Function this1 [] (
    E.Function this2 [] (
        !^this1 +% !^this2
    )
)

Outputs:

1
2
3
4
5
6
7
8
9
10
11
(function ()
 {
   return (function ()
           {
             var _this = this;
             return (function ()
                     {
                       return _this + this;
                     });
           });
 })()

How will these improvements benefit the WebSharper™ ecosystem?

  • the output code of WebSharper™ projects will be leaner
  • macros will be a lot easier to write
  • the compiler will be smaller and simpler

In subsequent posts on the JavaScript optimization effort I will cover:

  • JavaScript Code Model (a form of CodeDOM for JavaScript)
  • Global and local tail call optimizations

Stay tuned!

By Anton Tayanovskyy on Monday, June 14, 2010 — 0 comments

WebSharper™: Towards Automated JavaScript BindingsCore team

This blog describes the pre-release WebSharper Extensibility Framework.

How would I call reasonably complex JavaScript functions from WebSharper? For an example, consider jQuery.ajax.

A first attempt would look like this:

1
2
[<Inline "jQuery.ajax($settings)">]
let ajax (settings: obj) : obj = null

This is hardly acceptable as it throws away all the information present on the documentation page and makes it the user's responsibility to figure out what exactly the ajax function expects. But spelling out the precise types requires a lot more work.

In practice, a big part of WebSharper codebase turns out to consist of stubs like these - classes and functions that instruct F# how to call a particular JavaScript API (think jQuery, Ext JS) and provide types for the API. The WebSharper JavaScript-binding code is repetitive, tedious to write and maintain and not straightforward to generate.

At IntelliFactory we have been exprimenting with several approaches to the problem, culminating in something we currently call the Extensibility Framework, or EF for short. The basic idea behind EF is that instead of writing the bindings by hand, we use an F#-embedded DSL to describe them.

jQuery.ajax with EF might look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let private AjaxConfig =
    Pattern.Config "AjaxConfig" [] [
        "async" =~ T<bool>
        "beforeSend" =~ J.XMLHttpRequest ^-> T<unit>
        "cache" =~ T<bool>
        "complete" =~ J.XMLHttpRequest * T<string> ^-> T<unit>
        "contentType" =~ T<string>
        "context" =~ T<obj>
        // ..
    ]

    let private JQueryClass =
        Code.Class "JQuery"
        |=> JQuery
        |+> [
             "jQuery.ajax" => AjaxConfig ^-> T<unit>
             "jQuery.ajaxSetup" => AjaxConfig ^-> T<unit>
             "jQuery.contains" => 
                 J.Element?container * J.Node?contained ^-> T<bool>
        // ...

The use of the function would then look like this:

1
jQuery.Ajax(AjaxConfig(Async = false, ...))

The good news are several:

  • This is code-generating code - repetitive patterns can be abstracted over with plain functions in F#.
  • If a particular framework provides good documentation, this documentation can be parsed into EF values and then amended by merging it with hand-coded EF values where needed. Bindings generation is then semi-automatic.
  • Some common code-generating patterns will come with EF. Consider Pattern.Config above which generates a new configuration object class with the given required and optional fields.
  • Overload generation is automated. In EF, the type for a parameter that accepts either an int or a string can be spelled as T + T. The framework then figures out the correct overloads.

There is nothing particularly blog-worthy in the implementation of EF. It is mostly about figuring out the right interface (the most simple and yet diffuclt task there is). I will mention just one implementation detail I am particularly fond of. It is the use of F# operator overloading to describe method and function types. For example, these equalities are made to hold:

1
2
T<int -> int -> int> = T<int> ^-> T<int> ^-> T<int>
T<int * int -> int> = T<int> * T<int> ^-> T<int>
By Adam Granicz on Saturday, May 22, 2010 — 0 comments

WebSharper 2010 Standard is availableCore team

These are exciting times for the F# world! Monday, April 12, witnessed the launch of Visual Studio 2010 and the release of the official F# 2.0. Great job, F# team!

On our part, today we are pleased to announce the availability of WebSharper™ Platform 2010, version 1.0.

WebSharper™ is a platform for developing web applications in F# which includes:

  • A compiler from F# assemblies to JavaScript. WebSharper™ applications implement all client-side and server-side logic in F#, and run the client-side logic in JavaScript.
  • Support for nearly the entire F# language, many core F# libraries, and some .NET standard libraries in the JavaScript environment.
  • A custom RPC protocol for seamlessly communicating between the client and the server.
  • ASP.NET integration, with a way to package and deploy mixed client/server components, and manage their resource dependencies.
  • Visual Studio 2008 and 2010 integration with a WebSharper project template, build enhancements, and error location reporting.

The main highlights of this release are below.

Licensing

WebSharper™ 2010 Standard is available free of charge for both commercial and non-commercial purposes. We offer various support packages for individuals to large workgroups, and even entire enterprises, and premium extensions on our Purchase page. We also have a full range of training courses, consultation and expert services available. For more details, please send an email to sales@, or use our contact form.

The compiler

  • The error reporting has been much improved since the beta release. The compiler reports errors and warnings in bulk. Most messages carry source locations, allowing to click on them in Visual Studio.
  • The compilation of assemblies has been separated to avoid unnecessary recompilation, improving compilation time.
  • There are numerous improvements in the output code, to make it more compact, readable and efficient.

The standard library support

  • Support for Set<'T> and Map<'T1,'T2> with a backend based on AVL trees.
  • Support for System.DateTime and System.TimeSpan. Support for passing System.DateTime objects over RPC calls.

The language support

  • Thanks to the improvements in the recent F# compiler, constructors are no longer special-cased. Just like ordinary methods, they can now be marked with JavaScriptAttribute and implemented in F#.
  • More native JavaScript functionality is exposed for F# consumption, including such classes as JConsole, JDate, JObject (for JavaScript Console, Date and Object respectively).
  • Dom and jQuery bindings are likewise exposed for F#.

ASP.NET integration

  • WebSharper™ now integrates via an IHttpModule, detecting RPC call requests by a special header. This solution is robust to deploying WebSharper™ applications in arbitrary virtual folders.

The installer

  • Installation of templates for both Visual Studio 2008 and 2010, on 64 and 32-bit platforms.
  • Support for in-place upgrades and hotfix releases - the new versions of WebSharper™ 1.0 will be distributed as installers that will not require you to make any changes to your WebSharper™ projects in order to benefit from the latest versions' improvements.

We would love to hear from you! You can access a ton of information about WebSharper™, or its growing collection of extensions on the WebSharper™ home page.

By Adam Granicz on Wednesday, February 10, 2010 — 0 comments

WebSharper 2010 Standard coming soonCore team

Hi everyone, and thanks for the emails asking about the delay in launching WebSharper 2010 Standard. A few days ago an internal release of Visual Studio 2010 RC was made available by Microsoft to various industry partners including ourselves for testing before the public release. As it came right at our official launch date we had to make the hard decision to “silently” postpone releasing WebSharper 2010 Standard until we finished thoroughly testing it on the new Visual Studio.

Now that VS 2010 RC is publicly available, we can finally let you know about the delay. There is a long list of enhancements that have gone into the 2010 Standard product line that were not available in our previous trial drops, and we are excited about this new release bringing a truly unbeatable value.

By Anton Tayanovskyy on Monday, January 25, 2010 — 0 comments

WebSharper 0.4.74Core team

A new release of WebSharper (0.4.74) is made available for download today. It contains bugfixes, an improved RPC system that has been revised for optimal performance, and various improvements to the Formlets API. Formlet rendering configuration is now parameterized, allowing, for example, to alternate the row colors in formlet tables. Several new formlets (radio button groups and multi-select check boxes) have been added to the collection.

We are currently working towards a major release scheduled on February 9. The new release will finalize the APIs and bring major improvements to WebSharper builds and error reporting.

By Anton Tayanovskyy on Thursday, January 7, 2010 — 0 comments

Default Constructors and the Singleton PatternCore team

In this blog I will demonstrate a common F# idiom for passing values through the type system.

The need for this usually comes as you are trying to trick F# into doing something advanced. Typically, you write a function F accepting a type paremeter 'T and expecting to use some functionality that 'T provides. Passing instances of 'T is not always a good option, as passing types is much cheaper syntactically (thanks to the type inferencer).

This can be done by constraining 'T to implement an interface I. However, unlike Java, .NET interfaces cannot constrain static members. Thankfully, this can be resolved by default constructor constraints and on the type coupled with type initialization.

1
2
3
4
5
6
    type IFoo =
        abstract member Bar: unit -> unit

    let F<'T when 'T :> IFoo and 'T : (new : unit -> 'T)>() =
        let t = new 'T()
        t.Bar()

The remaining problem is the generated GC load, as new instances of 'T are created at every invocation of F.
A way to go here is to use the Singleton pattern:

1
2
3
4
5
6
7
8
9
10
    [<Sealed>]
    type Singleton<'T when 'T : (new : unit -> 'T)> private () =
        static let instance : 'T = new 'T()
        static member Instance : 'T = instance

    type IFoo =
        abstract member Bar: unit -> unit

    let F<'T when 'T :> IFoo and 'T : (new : unit -> 'T)>() =
        Singleton<'T>.Instance.Bar()

The GC time advantages of using the singleton can be easily measured:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module A = 
    let F<'T when 'T :> IFoo and 'T : (new : unit -> 'T)>() =
        (new 'T() :> IFoo).Bar()

    let G<'T when 'T :> IFoo and 'T : (new : unit -> 'T)>() =
        (Singleton<'T>.Instance :> IFoo).Bar()

#time    

for f in 0 .. 10000000 do
    A.F<Foo>()

// Real: 00:00:01.465, CPU: 00:00:01.453, GC gen0: 114, gen1: 0, gen2: 0

for f in 0 .. 10000000 do
    A.G<Foo>()

// Real: 00:00:00.544, CPU: 00:00:00.546, GC gen0: 0, gen1: 0, gen2: 0
By Adam Granicz on Wednesday, December 23, 2009 — 0 comments

WebSharper 0.4.62 is available - with dependent formlets-flowlets-third-party extensions-and more!Core team

We are happy to announce the availability of WebSharper 0.4.62 - the latest version of the WebSharper Platform that aims to equip professional F# developers with the right platform to rapidly develop rich, scalable, client-based web applications. This is the first release candidate of WebSharper Platform 2010 - our commercial offering for client-based reactive web development with F#. In this release there are a number of new features, including:

  • Dependent formlets - an embedded DSL for describing formlets whose parts depend on other parts of the same or other formlets.
  • Flowlets - an embedded DSL for describing sequences of web forms (such as steps in a registration page) as a strongly typed, first-class value in F#.
  • Extensions for the Google Maps API - you can build rich, interactive maps, street views, route planners, and other navigational functionality using the Google Maps API through WebSharper bindings - all with F# code and without a single line of JavaScript.
  • Extensions for the Google Visualization API - you can create stunning interactive visualizations (maps, charts, graphs, gauges, etc.) using the Google Visualization API through WebSharper - again, all with F# code.
  • First-class resources - pagelets can define their dependencies and the resources they need inside the F# type system, making it type-safe and robust, and freeing you from having to track various artifacts (style sheets, images, includes, etc.).

Go and grab your copy at our download page, or check out the demos we have online (and don't forget to use the drop-down on the right to see all demos). More demos, tutorials, and some long-awaited screencasts will be coming shortly.
One last bit: you may get exceptions in Visual Studio debug mode (which is misleading, as most of your WebSharper code will be executing in the client browser) from WebSharper code that performs HTML construction - you can safely ignore these as the WebSharper ASP.NET integration layer will take care of them. We are working on removing this annoyance in the next release candidate.

By Anton Tayanovskyy on Friday, December 11, 2009 — 0 comments

Foldr or FoldBack on Infinite F# SequencesCore team

A noticeable omission in F# standard library is Seq.foldBack, or the famous Haskell foldr. The semantics of foldr is very simple to remember: it replaces the native cons and nil of a list with arbitrary computations:

1
2
    foldr cons nil []     = nil
    foldr cons nil (x:xs) = cons x (foldr cons nil xs)

In particular, replacing the native cons and nil with themselves is always equivalent to the original list, e.g. forall x: foldr (:) [] x == x

Surprisingly, the above equation holds for infinite lists as well. This is something important to remember when porting these ideas to F#.

A naive F# translation would use this type:

1
 foldBack : ('T1 -> 'T2 -> 'T2) -> 'T1 -> seq<'T1> -> 'T2

However, by being strict in the second argument, cons will now prematurely force the evaluation of infinite sequences.

Here is a more faithful translation using LazyList from the FSharp.PowerPack.dll:

1
2
3
4
5
6
    /// Implements the lazy right-to-left fold.
    let foldBack (f: 'T1 -> Lazy<'T2> -> 'T2) (z: 'T2) (xs: seq<'T1>) : 'T2 =
        let rec foldr = function
            | LazyList.Nil         -> z
            | LazyList.Cons(x, xs) -> f x (lazy (foldr xs))
        foldr (LazyList.ofSeq xs)

Now let us test the code to make sure we have been faithful to Haskell in our translation:

1
2
3
4
5
6
7
8
    Seq.FoldBack 
        (fun x xs -> LazyList.consDelayed x (fun () -> Lazy.force xs)) 
        (LazyList.empty ())
        (Seq.initInfinite (fun x -> x))
    |> LazyList.toSeq
    |> Seq.take 10
    |> Seq.toArray
    |> printfn "%A"